This is an automated email from the ASF dual-hosted git repository.
zhangliang pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/shardingsphere.git
The following commit(s) were added to refs/heads/master by this push:
new 428af0d11cc Add lock timeout in DistSQL LOCK CLUSTER WITH lockStrategy
and UNLOCK CLUSTER (#34169)
428af0d11cc is described below
commit 428af0d11cc8442817bebbc1896987757509f36b
Author: cccchen <[email protected]>
AuthorDate: Fri Dec 27 14:09:09 2024 +0800
Add lock timeout in DistSQL LOCK CLUSTER WITH lockStrategy and UNLOCK
CLUSTER (#34169)
* Add lock timeout in DistSQL
* Modify the parameter name and type, fix checkstyle.
* Update document of DistSQL
* fix checkstyle
---
.../distsql/syntax/ral/lock-cluster-with.cn.md | 53 ++++++++++++++++++++++
.../distsql/syntax/ral/lock-cluster-with.en.md | 50 ++++++++++++++++++++
.../distsql/syntax/ral/unlock-cluster.cn.md | 52 +++++++++++++++++++++
.../distsql/syntax/ral/unlock-cluster.en.md | 48 ++++++++++++++++++++
.../engine/src/main/antlr4/imports/Keyword.g4 | 4 ++
.../engine/src/main/antlr4/imports/RALStatement.g4 | 4 +-
.../core/kernel/KernelDistSQLStatementVisitor.java | 4 +-
.../ral/updatable/LockClusterStatement.java | 8 ++++
.../ral/updatable/UnlockClusterStatement.java | 8 ++++
.../distsql/ral/updatable/LockClusterExecutor.java | 4 +-
.../ral/updatable/UnlockClusterExecutor.java | 4 +-
.../ral/updatable/LockClusterExecutorTest.java | 12 ++++-
.../ral/updatable/UnlockClusterExecutorTest.java | 11 ++++-
13 files changed, 251 insertions(+), 11 deletions(-)
diff --git
a/docs/document/content/user-manual/shardingsphere-proxy/distsql/syntax/ral/lock-cluster-with.cn.md
b/docs/document/content/user-manual/shardingsphere-proxy/distsql/syntax/ral/lock-cluster-with.cn.md
new file mode 100644
index 00000000000..ad51c5bafbb
--- /dev/null
+++
b/docs/document/content/user-manual/shardingsphere-proxy/distsql/syntax/ral/lock-cluster-with.cn.md
@@ -0,0 +1,53 @@
++++
+title = "LOCK CLUSTER WITH"
+weight = 16
++++
+
+### 描述
+
+`LOCK CLUSTER WITH` 语法用于向 `CLUSTER` 施加特定算法的锁。
+
+### 语法
+
+{{< tabs >}}
+{{% tab name="语法" %}}
+```sql
+LockClusterWith ::=
+ 'LOCK' 'CLUSTER' 'WITH' lockStrategy ('TIMEOUT' timeoutMillis)?
+
+timeoutmillis ::=
+ long
+```
+{{% /tab %}}
+{{% tab name="铁路图" %}}
+<iframe frameborder="0" name="diagram" id="diagram" width="100%"
height="100%"></iframe>
+{{% /tab %}}
+{{< /tabs >}}
+
+### 补充说明
+
+- 当 `CLUSTER` 已经处于被锁状态时,无法重复加锁,否则会抛出异常。
+- `lockStrategy` 当前支持两种锁策略,分别是排他锁 `WRITE` 与读写锁 `READ_WRITE`。
+- `timeoutMillis` 用于表明尝试加锁的超时时间,其单位为毫秒,未指定时,默认为 3000 毫秒。
+
+### 示例
+
+- 采用排他锁锁定 `CLUSTER` ,不设置超时时间
+
+```sql
+LOCK CLUSTER WITH WRITE;
+```
+
+- 采用读写锁锁定 `CLUSTER` ,并设置超时时间为 2000 毫秒
+
+```sql
+LOCK CLUSTER WITH READ_WRITE TIMEOUT 2000;
+```
+
+### 保留字
+
+`LOCK`、`CLUSTER`、`WITH`
+
+### 相关链接
+
+- [保留字](/cn/user-manual/shardingsphere-proxy/distsql/syntax/reserved-word/)
diff --git
a/docs/document/content/user-manual/shardingsphere-proxy/distsql/syntax/ral/lock-cluster-with.en.md
b/docs/document/content/user-manual/shardingsphere-proxy/distsql/syntax/ral/lock-cluster-with.en.md
new file mode 100644
index 00000000000..469e0386488
--- /dev/null
+++
b/docs/document/content/user-manual/shardingsphere-proxy/distsql/syntax/ral/lock-cluster-with.en.md
@@ -0,0 +1,50 @@
++++
+title = "LOCK CLUSTER WITH"
+weight = 16
++++
+
+### Description
+
+The `LOCK CLUSTER WITH` syntax is utilized to apply a lock with a specific
algorithm to the `CLUSTER`.
+
+### Syntax
+
+{{< tabs >}}
+{{% tab name="Grammar" %}}
+```sql
+LockClusterWith ::=
+ 'LOCK' 'CLUSTER' 'WITH' lockStrategy ('TIMEOUT' timeoutMillis)?
+
+timeoutmillis ::=
+ long
+```
+
+{{% /tab %}}
+{{% tab name="Railroad diagram" %}}
+
+<iframe frameborder="0" name="diagram" id="diagram" width="100%"
height="100%"></iframe>{{% /tab %}}{{< /tabs >}}
+
+### Supplement
+
+- When the `CLUSTER` is already locked, it is impossible to re-lock it,
otherwise an exception will be thrown.
+- Currently, the `lockStrategy` supports two lock strategies, namely the
exclusive lock `WRITE` and the read-write lock `READ_WRITE` .
+- The `timeoutMillis` is used to indicate the timeout period for attempting to
acquire the lock, with the unit being milliseconds. When not specified, the
default value is 3,000 milliseconds.
+
+### Example
+
+- Lock the `CLUSTER` with an exclusive lock without setting the timeout.
+```sql
+LOCK CLUSTER WITH WRITE;
+```
+- Lock the CLUSTER with a read-write lock and set the timeout to 2000
milliseconds.
+```sql
+LOCK CLUSTER WITH READ_WRITE TIMEOUT 2000;
+```
+
+### Reserved words
+
+`LOCK`,`CLUSTER`,`WITH`
+
+### Related links
+
+- [Reserved
word](/en/user-manual/shardingsphere-proxy/distsql/syntax/reserved-word/)
diff --git
a/docs/document/content/user-manual/shardingsphere-proxy/distsql/syntax/ral/unlock-cluster.cn.md
b/docs/document/content/user-manual/shardingsphere-proxy/distsql/syntax/ral/unlock-cluster.cn.md
new file mode 100644
index 00000000000..4fb0e462d2a
--- /dev/null
+++
b/docs/document/content/user-manual/shardingsphere-proxy/distsql/syntax/ral/unlock-cluster.cn.md
@@ -0,0 +1,52 @@
++++
+title = "UNLOCK CLUSTER"
+weight = 17
++++
+
+### 描述
+
+`UNLOCK CLUSTER` 语法用于解除通过 `LOCK CLUSTER WITH` 语句施加在 `CLUSTER` 上的锁。
+
+### 语法
+
+{{< tabs >}}
+{{% tab name="语法" %}}
+```sql
+UnlockCluster ::=
+ 'UNLOCK' 'CLUSTER' ('TIMEOUT' timeoutMillis)?
+
+timeoutmillis ::=
+ long
+```
+{{% /tab %}}
+{{% tab name="铁路图" %}}
+<iframe frameborder="0" name="diagram" id="diagram" width="100%"
height="100%"></iframe>
+{{% /tab %}}
+{{< /tabs >}}
+
+### 补充说明
+
+- 当 `CLUSTER` 不处于被锁状态时,无法解除锁,否则会抛出异常。
+- `timeoutMillis` 表明尝试解锁的超时时间,其单位为毫秒,未指定时,默认为 3000 毫秒。
+
+### 示例
+
+- 解锁 `CLUSTER` ,不设置超时时间。
+
+```sql
+UNLOCK CLUSTER;
+```
+
+- 解锁 `CLUSTER` ,并设置超时时间为 2000 毫秒。
+
+```sql
+UNLOCK CLUSTER TIMEOUT 2000;
+```
+
+### 保留字
+
+`UNLOCK`、`CLUSTER`
+
+### 相关链接
+
+- [保留字](/cn/user-manual/shardingsphere-proxy/distsql/syntax/reserved-word/)
diff --git
a/docs/document/content/user-manual/shardingsphere-proxy/distsql/syntax/ral/unlock-cluster.en.md
b/docs/document/content/user-manual/shardingsphere-proxy/distsql/syntax/ral/unlock-cluster.en.md
new file mode 100644
index 00000000000..b7114d80ccc
--- /dev/null
+++
b/docs/document/content/user-manual/shardingsphere-proxy/distsql/syntax/ral/unlock-cluster.en.md
@@ -0,0 +1,48 @@
++++
+title = "UNLOCK CLUSTER"
+weight = 17
++++
+
+### Description
+
+The `UNLOCK CLUSTER` syntax is used to release the lock applied to the
`CLUSTER` by the `LOCK CLUSTER WITH` statement.
+
+### Syntax
+
+{{< tabs >}}
+{{% tab name="Grammar" %}}
+```sql
+UnlockCluster ::=
+ 'UNLOCK' 'CLUSTER' ('TIMEOUT' timeoutMillis)?
+
+timeoutmillis ::=
+ long
+```
+
+{{% /tab %}}
+{{% tab name="Railroad diagram" %}}
+
+<iframe frameborder="0" name="diagram" id="diagram" width="100%"
height="100%"></iframe>{{% /tab %}}{{< /tabs >}}
+
+### Supplement
+
+- When the `CLUSTER` is not in a locked state, it is impossible to release the
lock; otherwise, an exception will be thrown.
+- `timeoutMillis` is used to indicate the timeout duration for attempting to
unlock, with the unit being milliseconds. When not specified, the default value
is 3,000 milliseconds.
+### Example
+
+- Unlock the `CLUSTER` without setting a timeout.
+```sql
+UNLOCK CLUSTER;
+```
+- Unlock the `CLUSTER` and set the timeout to 2000 milliseconds.
+```sql
+UNLOCK CLUSTER TIMEOUT 2000;
+```
+
+### Reserved words
+
+`UNLOCK`,`CLUSTER`
+
+### Related links
+
+- [Reserved
word](/en/user-manual/shardingsphere-proxy/distsql/syntax/reserved-word/)
diff --git a/parser/distsql/engine/src/main/antlr4/imports/Keyword.g4
b/parser/distsql/engine/src/main/antlr4/imports/Keyword.g4
index 310000c14ae..00e963e5536 100644
--- a/parser/distsql/engine/src/main/antlr4/imports/Keyword.g4
+++ b/parser/distsql/engine/src/main/antlr4/imports/Keyword.g4
@@ -342,3 +342,7 @@ FORCE
CHECK_PRIVILEGES
: C H E C K UL_ P R I V I L E G E S
;
+
+TIMEOUT
+ : T I M E O U T
+ ;
\ No newline at end of file
diff --git a/parser/distsql/engine/src/main/antlr4/imports/RALStatement.g4
b/parser/distsql/engine/src/main/antlr4/imports/RALStatement.g4
index 5d9e356e55f..e5f63ffc209 100644
--- a/parser/distsql/engine/src/main/antlr4/imports/RALStatement.g4
+++ b/parser/distsql/engine/src/main/antlr4/imports/RALStatement.g4
@@ -100,11 +100,11 @@ convertYamlConfiguration
;
lockCluster
- : LOCK CLUSTER WITH lockStrategy
+ : LOCK CLUSTER WITH lockStrategy (TIMEOUT INT_)?
;
unlockCluster
- : UNLOCK CLUSTER
+ : UNLOCK CLUSTER (TIMEOUT INT_)?
;
showPluginImplementations
diff --git
a/parser/distsql/engine/src/main/java/org/apache/shardingsphere/distsql/parser/core/kernel/KernelDistSQLStatementVisitor.java
b/parser/distsql/engine/src/main/java/org/apache/shardingsphere/distsql/parser/core/kernel/KernelDistSQLStatementVisitor.java
index 82f3e5c973a..c725b1e642c 100644
---
a/parser/distsql/engine/src/main/java/org/apache/shardingsphere/distsql/parser/core/kernel/KernelDistSQLStatementVisitor.java
+++
b/parser/distsql/engine/src/main/java/org/apache/shardingsphere/distsql/parser/core/kernel/KernelDistSQLStatementVisitor.java
@@ -322,12 +322,12 @@ public final class KernelDistSQLStatementVisitor extends
KernelDistSQLStatementB
@Override
public ASTNode visitLockCluster(final LockClusterContext ctx) {
- return new LockClusterStatement((AlgorithmSegment)
visitAlgorithmDefinition(ctx.lockStrategy().algorithmDefinition()));
+ return new LockClusterStatement((AlgorithmSegment)
visitAlgorithmDefinition(ctx.lockStrategy().algorithmDefinition()),
Long.parseLong(getIdentifierValue(ctx.INT_())));
}
@Override
public ASTNode visitUnlockCluster(final UnlockClusterContext ctx) {
- return new UnlockClusterStatement();
+ return new
UnlockClusterStatement(Long.parseLong(getIdentifierValue(ctx.INT_())));
}
private String getIdentifierValue(final ParseTree context) {
diff --git
a/parser/distsql/statement/src/main/java/org/apache/shardingsphere/distsql/statement/ral/updatable/LockClusterStatement.java
b/parser/distsql/statement/src/main/java/org/apache/shardingsphere/distsql/statement/ral/updatable/LockClusterStatement.java
index 215ab488578..04915e9038a 100644
---
a/parser/distsql/statement/src/main/java/org/apache/shardingsphere/distsql/statement/ral/updatable/LockClusterStatement.java
+++
b/parser/distsql/statement/src/main/java/org/apache/shardingsphere/distsql/statement/ral/updatable/LockClusterStatement.java
@@ -21,6 +21,8 @@ import lombok.Getter;
import lombok.RequiredArgsConstructor;
import org.apache.shardingsphere.distsql.segment.AlgorithmSegment;
+import java.util.Optional;
+
/**
* Lock cluster statement.
*/
@@ -29,4 +31,10 @@ import
org.apache.shardingsphere.distsql.segment.AlgorithmSegment;
public final class LockClusterStatement extends UpdatableRALStatement {
private final AlgorithmSegment lockStrategy;
+
+ private final Long timeoutMillis;
+
+ public Optional<Long> getTimeoutMillis() {
+ return Optional.of(timeoutMillis);
+ }
}
diff --git
a/parser/distsql/statement/src/main/java/org/apache/shardingsphere/distsql/statement/ral/updatable/UnlockClusterStatement.java
b/parser/distsql/statement/src/main/java/org/apache/shardingsphere/distsql/statement/ral/updatable/UnlockClusterStatement.java
index 8f588abd89d..fe584b661af 100644
---
a/parser/distsql/statement/src/main/java/org/apache/shardingsphere/distsql/statement/ral/updatable/UnlockClusterStatement.java
+++
b/parser/distsql/statement/src/main/java/org/apache/shardingsphere/distsql/statement/ral/updatable/UnlockClusterStatement.java
@@ -19,9 +19,17 @@ package
org.apache.shardingsphere.distsql.statement.ral.updatable;
import lombok.RequiredArgsConstructor;
+import java.util.Optional;
+
/**
* Unlock cluster statement.
*/
@RequiredArgsConstructor
public final class UnlockClusterStatement extends UpdatableRALStatement {
+
+ private final Long timeoutMillis;
+
+ public Optional<Long> getTimeoutMillis() {
+ return Optional.of(timeoutMillis);
+ }
}
diff --git
a/proxy/backend/core/src/main/java/org/apache/shardingsphere/proxy/backend/handler/distsql/ral/updatable/LockClusterExecutor.java
b/proxy/backend/core/src/main/java/org/apache/shardingsphere/proxy/backend/handler/distsql/ral/updatable/LockClusterExecutor.java
index f490b58143a..00cd54cd9fe 100644
---
a/proxy/backend/core/src/main/java/org/apache/shardingsphere/proxy/backend/handler/distsql/ral/updatable/LockClusterExecutor.java
+++
b/proxy/backend/core/src/main/java/org/apache/shardingsphere/proxy/backend/handler/distsql/ral/updatable/LockClusterExecutor.java
@@ -44,8 +44,8 @@ public final class LockClusterExecutor implements
DistSQLUpdateExecutor<LockClus
checkAlgorithm(sqlStatement);
LockContext lockContext =
contextManager.getComputeNodeInstanceContext().getLockContext();
GlobalLockDefinition lockDefinition = new GlobalLockDefinition(new
ClusterLock());
- // TODO should configured in SQL Statement
- if (lockContext.tryLock(lockDefinition, 3000L)) {
+ long timeoutMillis = sqlStatement.getTimeoutMillis().orElse(3000L);
+ if (lockContext.tryLock(lockDefinition, timeoutMillis)) {
try {
checkState(contextManager);
TypedSPILoader.getService(ClusterLockStrategy.class,
sqlStatement.getLockStrategy().getName()).lock();
diff --git
a/proxy/backend/core/src/main/java/org/apache/shardingsphere/proxy/backend/handler/distsql/ral/updatable/UnlockClusterExecutor.java
b/proxy/backend/core/src/main/java/org/apache/shardingsphere/proxy/backend/handler/distsql/ral/updatable/UnlockClusterExecutor.java
index 9b744e64956..94d992aaac8 100644
---
a/proxy/backend/core/src/main/java/org/apache/shardingsphere/proxy/backend/handler/distsql/ral/updatable/UnlockClusterExecutor.java
+++
b/proxy/backend/core/src/main/java/org/apache/shardingsphere/proxy/backend/handler/distsql/ral/updatable/UnlockClusterExecutor.java
@@ -39,8 +39,8 @@ public final class UnlockClusterExecutor implements
DistSQLUpdateExecutor<Unlock
checkState(contextManager);
LockContext lockContext =
contextManager.getComputeNodeInstanceContext().getLockContext();
GlobalLockDefinition lockDefinition = new GlobalLockDefinition(new
ClusterLock());
- // TODO should configured in SQL Statement
- if (lockContext.tryLock(lockDefinition, 3000L)) {
+ long timeoutMillis = sqlStatement.getTimeoutMillis().orElse(3000L);
+ if (lockContext.tryLock(lockDefinition, timeoutMillis)) {
try {
checkState(contextManager);
contextManager.getPersistServiceFacade().getStatePersistService().update(ClusterState.OK);
diff --git
a/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/handler/distsql/ral/updatable/LockClusterExecutorTest.java
b/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/handler/distsql/ral/updatable/LockClusterExecutorTest.java
index 00e5083fc0e..4fae2b0b407 100644
---
a/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/handler/distsql/ral/updatable/LockClusterExecutorTest.java
+++
b/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/handler/distsql/ral/updatable/LockClusterExecutorTest.java
@@ -32,6 +32,7 @@ import org.junit.jupiter.api.extension.ExtendWith;
import java.util.Properties;
import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import static org.mockito.Mockito.RETURNS_DEEP_STUBS;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
@@ -46,13 +47,20 @@ class LockClusterExecutorTest {
void assertExecuteUpdateWithLockedCluster() {
ContextManager contextManager = mock(ContextManager.class,
RETURNS_DEEP_STUBS);
when(contextManager.getStateContext().getClusterState()).thenReturn(ClusterState.UNAVAILABLE);
- assertThrows(LockedClusterException.class, () ->
executor.executeUpdate(new LockClusterStatement(new AlgorithmSegment("FOO", new
Properties())), contextManager));
+ assertThrows(LockedClusterException.class, () ->
executor.executeUpdate(new LockClusterStatement(new AlgorithmSegment("FOO", new
Properties()), null), contextManager));
}
@Test
void assertExecuteUpdateWithWrongAlgorithm() {
ContextManager contextManager = mock(ContextManager.class,
RETURNS_DEEP_STUBS);
when(contextManager.getStateContext().getClusterState()).thenReturn(ClusterState.OK);
- assertThrows(ServiceProviderNotFoundException.class, () ->
executor.executeUpdate(new LockClusterStatement(new AlgorithmSegment("FOO", new
Properties())), contextManager));
+ assertThrows(ServiceProviderNotFoundException.class, () ->
executor.executeUpdate(new LockClusterStatement(new AlgorithmSegment("FOO", new
Properties()), null), contextManager));
+ }
+
+ @Test
+ void assertExecuteUpdateWithUsingTimeout() {
+ ContextManager contextManager = mock(ContextManager.class,
RETURNS_DEEP_STUBS);
+
when(contextManager.getStateContext().getClusterState()).thenReturn(ClusterState.OK);
+ assertDoesNotThrow(() -> executor.executeUpdate(new
LockClusterStatement(new AlgorithmSegment("WRITE", new Properties()), 2000L),
contextManager));
}
}
diff --git
a/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/handler/distsql/ral/updatable/UnlockClusterExecutorTest.java
b/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/handler/distsql/ral/updatable/UnlockClusterExecutorTest.java
index 02edc049cd9..076ff500c77 100644
---
a/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/handler/distsql/ral/updatable/UnlockClusterExecutorTest.java
+++
b/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/handler/distsql/ral/updatable/UnlockClusterExecutorTest.java
@@ -28,6 +28,7 @@ import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import static org.mockito.Mockito.RETURNS_DEEP_STUBS;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
@@ -43,6 +44,14 @@ class UnlockClusterExecutorTest {
ContextManager contextManager = mock(ContextManager.class,
RETURNS_DEEP_STUBS);
when(contextManager.getStateContext().getClusterState()).thenReturn(ClusterState.OK);
when(ProxyContext.getInstance().getContextManager()).thenReturn(contextManager);
- assertThrows(NotLockedClusterException.class, () ->
executor.executeUpdate(new UnlockClusterStatement(), contextManager));
+ assertThrows(NotLockedClusterException.class, () ->
executor.executeUpdate(new UnlockClusterStatement(null), contextManager));
+ }
+
+ @Test
+ void assertExecuteUpdateWithUsingTimeout() {
+ ContextManager contextManager = mock(ContextManager.class,
RETURNS_DEEP_STUBS);
+
when(contextManager.getStateContext().getClusterState()).thenReturn(ClusterState.UNAVAILABLE);
+
when(ProxyContext.getInstance().getContextManager()).thenReturn(contextManager);
+ assertDoesNotThrow(() -> executor.executeUpdate(new
UnlockClusterStatement(2000L), contextManager));
}
}