This is an automated email from the ASF dual-hosted git repository.

terrymanu 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 de019fb9713 Decouple cluster lock strategies from Proxy runtime 
(#40050)
de019fb9713 is described below

commit de019fb9713f6a0e9ea2e30e5bda3e6c7bd25c89
Author: Liang Zhang <[email protected]>
AuthorDate: Sun Oct 4 20:11:03 2026 +0800

    Decouple cluster lock strategies from Proxy runtime (#40050)
---
 .../lock/impl/ClusterReadWriteLockStrategy.java    |  8 ++--
 .../lock/impl/ClusterWriteLockStrategy.java        |  8 ++--
 .../ral/updatable/lock/LockClusterExecutor.java    |  2 +-
 ...de.manager.cluster.lock.spi.ClusterLockStrategy |  4 +-
 .../update/DistSQLUpdateExecuteEngineTest.java     | 15 ++++++++
 .../impl/ClusterReadWriteLockStrategyTest.java     | 30 +++++++--------
 .../lock/impl/ClusterWriteLockStrategyTest.java    | 30 +++++++--------
 .../updatable/lock/LockClusterExecutorTest.java    | 43 ++++++++--------------
 .../statement/DistSQLStatementExecutorTest.java    | 41 +++++++++++++++++++++
 .../cluster/lock/spi/ClusterLockStrategy.java      |  8 +++-
 .../DistSQLUpdateProxyBackendHandlerTest.java      | 37 +++++++++++++++++++
 11 files changed, 156 insertions(+), 70 deletions(-)

diff --git 
a/proxy/backend/core/src/main/java/org/apache/shardingsphere/proxy/backend/lock/impl/ClusterReadWriteLockStrategy.java
 
b/infra/distsql-handler/src/main/java/org/apache/shardingsphere/distsql/handler/executor/lock/impl/ClusterReadWriteLockStrategy.java
similarity index 79%
rename from 
proxy/backend/core/src/main/java/org/apache/shardingsphere/proxy/backend/lock/impl/ClusterReadWriteLockStrategy.java
rename to 
infra/distsql-handler/src/main/java/org/apache/shardingsphere/distsql/handler/executor/lock/impl/ClusterReadWriteLockStrategy.java
index 487151f3c17..5ede4a4ea54 100644
--- 
a/proxy/backend/core/src/main/java/org/apache/shardingsphere/proxy/backend/lock/impl/ClusterReadWriteLockStrategy.java
+++ 
b/infra/distsql-handler/src/main/java/org/apache/shardingsphere/distsql/handler/executor/lock/impl/ClusterReadWriteLockStrategy.java
@@ -15,11 +15,11 @@
  * limitations under the License.
  */
 
-package org.apache.shardingsphere.proxy.backend.lock.impl;
+package org.apache.shardingsphere.distsql.handler.executor.lock.impl;
 
+import org.apache.shardingsphere.mode.manager.ContextManager;
 import 
org.apache.shardingsphere.mode.manager.cluster.lock.spi.ClusterLockStrategy;
 import org.apache.shardingsphere.mode.state.ShardingSphereState;
-import org.apache.shardingsphere.proxy.backend.context.ProxyContext;
 
 /**
  * Cluster read-write lock strategy.
@@ -27,8 +27,8 @@ import 
org.apache.shardingsphere.proxy.backend.context.ProxyContext;
 public class ClusterReadWriteLockStrategy implements ClusterLockStrategy {
     
     @Override
-    public void lock() {
-        
ProxyContext.getInstance().getContextManager().getPersistServiceFacade().getStateService().update(ShardingSphereState.UNAVAILABLE);
+    public void lock(final ContextManager contextManager) {
+        
contextManager.getPersistServiceFacade().getStateService().update(ShardingSphereState.UNAVAILABLE);
     }
     
     @Override
diff --git 
a/proxy/backend/core/src/main/java/org/apache/shardingsphere/proxy/backend/lock/impl/ClusterWriteLockStrategy.java
 
b/infra/distsql-handler/src/main/java/org/apache/shardingsphere/distsql/handler/executor/lock/impl/ClusterWriteLockStrategy.java
similarity index 79%
rename from 
proxy/backend/core/src/main/java/org/apache/shardingsphere/proxy/backend/lock/impl/ClusterWriteLockStrategy.java
rename to 
infra/distsql-handler/src/main/java/org/apache/shardingsphere/distsql/handler/executor/lock/impl/ClusterWriteLockStrategy.java
index 24affb5dce7..5ca2b45be57 100644
--- 
a/proxy/backend/core/src/main/java/org/apache/shardingsphere/proxy/backend/lock/impl/ClusterWriteLockStrategy.java
+++ 
b/infra/distsql-handler/src/main/java/org/apache/shardingsphere/distsql/handler/executor/lock/impl/ClusterWriteLockStrategy.java
@@ -15,11 +15,11 @@
  * limitations under the License.
  */
 
-package org.apache.shardingsphere.proxy.backend.lock.impl;
+package org.apache.shardingsphere.distsql.handler.executor.lock.impl;
 
+import org.apache.shardingsphere.mode.manager.ContextManager;
 import 
org.apache.shardingsphere.mode.manager.cluster.lock.spi.ClusterLockStrategy;
 import org.apache.shardingsphere.mode.state.ShardingSphereState;
-import org.apache.shardingsphere.proxy.backend.context.ProxyContext;
 
 /**
  * Cluster write lock strategy.
@@ -27,8 +27,8 @@ import 
org.apache.shardingsphere.proxy.backend.context.ProxyContext;
 public class ClusterWriteLockStrategy implements ClusterLockStrategy {
     
     @Override
-    public void lock() {
-        
ProxyContext.getInstance().getContextManager().getPersistServiceFacade().getStateService().update(ShardingSphereState.READ_ONLY);
+    public void lock(final ContextManager contextManager) {
+        
contextManager.getPersistServiceFacade().getStateService().update(ShardingSphereState.READ_ONLY);
     }
     
     @Override
diff --git 
a/infra/distsql-handler/src/main/java/org/apache/shardingsphere/distsql/handler/executor/ral/updatable/lock/LockClusterExecutor.java
 
b/infra/distsql-handler/src/main/java/org/apache/shardingsphere/distsql/handler/executor/ral/updatable/lock/LockClusterExecutor.java
index 5d0ce9cc893..de798712662 100644
--- 
a/infra/distsql-handler/src/main/java/org/apache/shardingsphere/distsql/handler/executor/ral/updatable/lock/LockClusterExecutor.java
+++ 
b/infra/distsql-handler/src/main/java/org/apache/shardingsphere/distsql/handler/executor/ral/updatable/lock/LockClusterExecutor.java
@@ -43,7 +43,7 @@ public final class LockClusterExecutor implements 
DistSQLUpdateExecutor<LockClus
         checkAlgorithm(sqlStatement);
         contextManager.getExclusiveOperatorEngine().operate(new 
LockClusterOperation(), sqlStatement.getTimeoutMillis(), () -> {
             checkState(contextManager);
-            TypedSPILoader.getService(ClusterLockStrategy.class, 
sqlStatement.getLockStrategy().getName()).lock();
+            TypedSPILoader.getService(ClusterLockStrategy.class, 
sqlStatement.getLockStrategy().getName()).lock(contextManager);
         });
     }
     
diff --git 
a/proxy/backend/core/src/main/resources/META-INF/services/org.apache.shardingsphere.mode.manager.cluster.lock.spi.ClusterLockStrategy
 
b/infra/distsql-handler/src/main/resources/META-INF/services/org.apache.shardingsphere.mode.manager.cluster.lock.spi.ClusterLockStrategy
similarity index 81%
rename from 
proxy/backend/core/src/main/resources/META-INF/services/org.apache.shardingsphere.mode.manager.cluster.lock.spi.ClusterLockStrategy
rename to 
infra/distsql-handler/src/main/resources/META-INF/services/org.apache.shardingsphere.mode.manager.cluster.lock.spi.ClusterLockStrategy
index 1fafee094fc..fe9f0043dc4 100644
--- 
a/proxy/backend/core/src/main/resources/META-INF/services/org.apache.shardingsphere.mode.manager.cluster.lock.spi.ClusterLockStrategy
+++ 
b/infra/distsql-handler/src/main/resources/META-INF/services/org.apache.shardingsphere.mode.manager.cluster.lock.spi.ClusterLockStrategy
@@ -15,5 +15,5 @@
 # limitations under the License.
 #
 
-org.apache.shardingsphere.proxy.backend.lock.impl.ClusterWriteLockStrategy
-org.apache.shardingsphere.proxy.backend.lock.impl.ClusterReadWriteLockStrategy
+org.apache.shardingsphere.distsql.handler.executor.lock.impl.ClusterWriteLockStrategy
+org.apache.shardingsphere.distsql.handler.executor.lock.impl.ClusterReadWriteLockStrategy
diff --git 
a/infra/distsql-handler/src/test/java/org/apache/shardingsphere/distsql/handler/engine/update/DistSQLUpdateExecuteEngineTest.java
 
b/infra/distsql-handler/src/test/java/org/apache/shardingsphere/distsql/handler/engine/update/DistSQLUpdateExecuteEngineTest.java
index 68b39315d76..bcc7db5a712 100644
--- 
a/infra/distsql-handler/src/test/java/org/apache/shardingsphere/distsql/handler/engine/update/DistSQLUpdateExecuteEngineTest.java
+++ 
b/infra/distsql-handler/src/test/java/org/apache/shardingsphere/distsql/handler/engine/update/DistSQLUpdateExecuteEngineTest.java
@@ -27,7 +27,9 @@ import 
org.apache.shardingsphere.distsql.handler.engine.update.rdl.rule.spi.data
 import 
org.apache.shardingsphere.distsql.handler.engine.update.rdl.rule.spi.global.GlobalRuleDefinitionExecutor;
 import 
org.apache.shardingsphere.distsql.handler.engine.update.spi.AdvancedDistSQLUpdateExecutor;
 import 
org.apache.shardingsphere.distsql.handler.engine.update.spi.DistSQLUpdateExecutor;
+import org.apache.shardingsphere.distsql.segment.AlgorithmSegment;
 import org.apache.shardingsphere.distsql.statement.DistSQLStatement;
+import 
org.apache.shardingsphere.distsql.statement.type.ral.updatable.LockClusterStatement;
 import 
org.apache.shardingsphere.distsql.statement.type.rdl.rule.database.DatabaseRuleDefinitionStatement;
 import 
org.apache.shardingsphere.distsql.statement.type.rdl.rule.global.GlobalRuleDefinitionStatement;
 import org.apache.shardingsphere.infra.config.rule.RuleConfiguration;
@@ -35,6 +37,7 @@ import 
org.apache.shardingsphere.infra.metadata.database.ShardingSphereDatabase;
 import org.apache.shardingsphere.infra.metadata.database.rule.RuleMetaData;
 import org.apache.shardingsphere.infra.rule.ShardingSphereRule;
 import org.apache.shardingsphere.infra.spi.type.typed.TypedSPILoader;
+import org.apache.shardingsphere.mode.exception.NotClusterModeException;
 import org.apache.shardingsphere.mode.manager.ContextManager;
 import 
org.apache.shardingsphere.mode.persist.service.MetaDataManagerPersistService;
 import 
org.apache.shardingsphere.sql.parser.statement.core.statement.attribute.type.FromDatabaseSQLStatementAttribute;
@@ -43,8 +46,12 @@ import org.mockito.MockedStatic;
 
 import java.sql.SQLException;
 import java.util.Optional;
+import java.util.Properties;
 
 import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyLong;
 import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.Mockito.RETURNS_DEEP_STUBS;
 import static org.mockito.Mockito.mock;
@@ -57,6 +64,14 @@ import static org.mockito.Mockito.withSettings;
 @SuppressWarnings("unchecked")
 class DistSQLUpdateExecuteEngineTest {
     
+    @Test
+    void assertExecuteUpdateWithLockClusterInStandaloneMode() throws 
SQLException {
+        ContextManager contextManager = mock(ContextManager.class, 
RETURNS_DEEP_STUBS);
+        LockClusterStatement sqlStatement = new LockClusterStatement(new 
AlgorithmSegment("WRITE", new Properties()));
+        assertThrows(NotClusterModeException.class, () -> new 
DistSQLUpdateExecuteEngine(sqlStatement, null, contextManager, 
null).executeUpdate());
+        verify(contextManager.getExclusiveOperatorEngine(), 
never()).operate(any(), anyLong(), any());
+    }
+    
     @Test
     void assertExecuteUpdateWithGlobalRuleDefinitionStatement() throws 
SQLException {
         GlobalRuleDefinitionStatement sqlStatement = 
mock(GlobalRuleDefinitionStatement.class, RETURNS_DEEP_STUBS);
diff --git 
a/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/lock/impl/ClusterReadWriteLockStrategyTest.java
 
b/infra/distsql-handler/src/test/java/org/apache/shardingsphere/distsql/handler/executor/lock/impl/ClusterReadWriteLockStrategyTest.java
similarity index 58%
rename from 
proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/lock/impl/ClusterReadWriteLockStrategyTest.java
rename to 
infra/distsql-handler/src/test/java/org/apache/shardingsphere/distsql/handler/executor/lock/impl/ClusterReadWriteLockStrategyTest.java
index 16be664878c..7f897269c80 100644
--- 
a/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/lock/impl/ClusterReadWriteLockStrategyTest.java
+++ 
b/infra/distsql-handler/src/test/java/org/apache/shardingsphere/distsql/handler/executor/lock/impl/ClusterReadWriteLockStrategyTest.java
@@ -15,36 +15,36 @@
  * limitations under the License.
  */
 
-package org.apache.shardingsphere.proxy.backend.lock.impl;
+package org.apache.shardingsphere.distsql.handler.executor.lock.impl;
 
 import org.apache.shardingsphere.infra.spi.type.typed.TypedSPILoader;
+import org.apache.shardingsphere.mode.manager.ContextManager;
 import 
org.apache.shardingsphere.mode.manager.cluster.lock.spi.ClusterLockStrategy;
 import org.apache.shardingsphere.mode.state.ShardingSphereState;
-import org.apache.shardingsphere.mode.state.StatePersistService;
-import org.apache.shardingsphere.proxy.backend.context.ProxyContext;
-import 
org.apache.shardingsphere.test.infra.framework.extension.mock.AutoMockExtension;
-import 
org.apache.shardingsphere.test.infra.framework.extension.mock.StaticMockSettings;
 import org.junit.jupiter.api.Test;
-import org.junit.jupiter.api.extension.ExtendWith;
 
 import static org.mockito.Mockito.RETURNS_DEEP_STUBS;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
 
-@ExtendWith(AutoMockExtension.class)
-@StaticMockSettings(ProxyContext.class)
 class ClusterReadWriteLockStrategyTest {
     
     private final ClusterLockStrategy clusterLockStrategy = 
TypedSPILoader.getService(ClusterLockStrategy.class, "READ_WRITE");
     
     @Test
     void assertLock() {
-        StatePersistService stateService = mock(StatePersistService.class);
-        ProxyContext proxyContext = mock(ProxyContext.class, 
RETURNS_DEEP_STUBS);
-        
when(proxyContext.getContextManager().getPersistServiceFacade().getStateService()).thenReturn(stateService);
-        when(ProxyContext.getInstance()).thenReturn(proxyContext);
-        clusterLockStrategy.lock();
-        verify(stateService).update(ShardingSphereState.UNAVAILABLE);
+        ContextManager contextManager = mock(ContextManager.class, 
RETURNS_DEEP_STUBS);
+        clusterLockStrategy.lock(contextManager);
+        
verify(contextManager.getPersistServiceFacade().getStateService()).update(ShardingSphereState.UNAVAILABLE);
+    }
+    
+    @Test
+    void assertLockWithDifferentContextManagers() {
+        ContextManager contextManager = mock(ContextManager.class, 
RETURNS_DEEP_STUBS);
+        ContextManager anotherContextManager = mock(ContextManager.class, 
RETURNS_DEEP_STUBS);
+        clusterLockStrategy.lock(contextManager);
+        clusterLockStrategy.lock(anotherContextManager);
+        
verify(contextManager.getPersistServiceFacade().getStateService()).update(ShardingSphereState.UNAVAILABLE);
+        
verify(anotherContextManager.getPersistServiceFacade().getStateService()).update(ShardingSphereState.UNAVAILABLE);
     }
 }
diff --git 
a/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/lock/impl/ClusterWriteLockStrategyTest.java
 
b/infra/distsql-handler/src/test/java/org/apache/shardingsphere/distsql/handler/executor/lock/impl/ClusterWriteLockStrategyTest.java
similarity index 58%
rename from 
proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/lock/impl/ClusterWriteLockStrategyTest.java
rename to 
infra/distsql-handler/src/test/java/org/apache/shardingsphere/distsql/handler/executor/lock/impl/ClusterWriteLockStrategyTest.java
index 7995ef19162..3485b8613bc 100644
--- 
a/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/lock/impl/ClusterWriteLockStrategyTest.java
+++ 
b/infra/distsql-handler/src/test/java/org/apache/shardingsphere/distsql/handler/executor/lock/impl/ClusterWriteLockStrategyTest.java
@@ -15,36 +15,36 @@
  * limitations under the License.
  */
 
-package org.apache.shardingsphere.proxy.backend.lock.impl;
+package org.apache.shardingsphere.distsql.handler.executor.lock.impl;
 
 import org.apache.shardingsphere.infra.spi.type.typed.TypedSPILoader;
+import org.apache.shardingsphere.mode.manager.ContextManager;
 import 
org.apache.shardingsphere.mode.manager.cluster.lock.spi.ClusterLockStrategy;
 import org.apache.shardingsphere.mode.state.ShardingSphereState;
-import org.apache.shardingsphere.mode.state.StatePersistService;
-import org.apache.shardingsphere.proxy.backend.context.ProxyContext;
-import 
org.apache.shardingsphere.test.infra.framework.extension.mock.AutoMockExtension;
-import 
org.apache.shardingsphere.test.infra.framework.extension.mock.StaticMockSettings;
 import org.junit.jupiter.api.Test;
-import org.junit.jupiter.api.extension.ExtendWith;
 
 import static org.mockito.Mockito.RETURNS_DEEP_STUBS;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
 
-@ExtendWith(AutoMockExtension.class)
-@StaticMockSettings(ProxyContext.class)
 class ClusterWriteLockStrategyTest {
     
     private final ClusterLockStrategy clusterLockStrategy = 
TypedSPILoader.getService(ClusterLockStrategy.class, "WRITE");
     
     @Test
     void assertLock() {
-        StatePersistService stateService = mock(StatePersistService.class);
-        ProxyContext proxyContext = mock(ProxyContext.class, 
RETURNS_DEEP_STUBS);
-        
when(proxyContext.getContextManager().getPersistServiceFacade().getStateService()).thenReturn(stateService);
-        when(ProxyContext.getInstance()).thenReturn(proxyContext);
-        clusterLockStrategy.lock();
-        verify(stateService).update(ShardingSphereState.READ_ONLY);
+        ContextManager contextManager = mock(ContextManager.class, 
RETURNS_DEEP_STUBS);
+        clusterLockStrategy.lock(contextManager);
+        
verify(contextManager.getPersistServiceFacade().getStateService()).update(ShardingSphereState.READ_ONLY);
+    }
+    
+    @Test
+    void assertLockWithDifferentContextManagers() {
+        ContextManager contextManager = mock(ContextManager.class, 
RETURNS_DEEP_STUBS);
+        ContextManager anotherContextManager = mock(ContextManager.class, 
RETURNS_DEEP_STUBS);
+        clusterLockStrategy.lock(contextManager);
+        clusterLockStrategy.lock(anotherContextManager);
+        
verify(contextManager.getPersistServiceFacade().getStateService()).update(ShardingSphereState.READ_ONLY);
+        
verify(anotherContextManager.getPersistServiceFacade().getStateService()).update(ShardingSphereState.READ_ONLY);
     }
 }
diff --git 
a/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/handler/distsql/ral/updatable/lock/LockClusterExecutorTest.java
 
b/infra/distsql-handler/src/test/java/org/apache/shardingsphere/distsql/handler/executor/ral/updatable/lock/LockClusterExecutorTest.java
similarity index 79%
rename from 
proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/handler/distsql/ral/updatable/lock/LockClusterExecutorTest.java
rename to 
infra/distsql-handler/src/test/java/org/apache/shardingsphere/distsql/handler/executor/ral/updatable/lock/LockClusterExecutorTest.java
index 7c726c823db..44380d31f19 100644
--- 
a/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/handler/distsql/ral/updatable/lock/LockClusterExecutorTest.java
+++ 
b/infra/distsql-handler/src/test/java/org/apache/shardingsphere/distsql/handler/executor/ral/updatable/lock/LockClusterExecutorTest.java
@@ -15,10 +15,9 @@
  * limitations under the License.
  */
 
-package 
org.apache.shardingsphere.proxy.backend.handler.distsql.ral.updatable.lock;
+package org.apache.shardingsphere.distsql.handler.executor.ral.updatable.lock;
 
 import 
org.apache.shardingsphere.distsql.handler.engine.update.spi.DistSQLUpdateExecutor;
-import 
org.apache.shardingsphere.distsql.handler.executor.ral.updatable.lock.LockClusterExecutor;
 import org.apache.shardingsphere.distsql.segment.AlgorithmSegment;
 import 
org.apache.shardingsphere.distsql.statement.type.ral.updatable.LockClusterStatement;
 import 
org.apache.shardingsphere.infra.algorithm.core.exception.MissingRequiredAlgorithmException;
@@ -30,10 +29,6 @@ import org.apache.shardingsphere.mode.manager.ContextManager;
 import 
org.apache.shardingsphere.mode.manager.cluster.lock.exception.LockedClusterException;
 import org.apache.shardingsphere.mode.state.ShardingSphereState;
 import org.apache.shardingsphere.mode.state.StatePersistService;
-import org.apache.shardingsphere.proxy.backend.context.ProxyContext;
-import 
org.apache.shardingsphere.test.infra.framework.extension.mock.AutoMockExtension;
-import 
org.apache.shardingsphere.test.infra.framework.extension.mock.StaticMockSettings;
-import org.junit.jupiter.api.extension.ExtendWith;
 import org.junit.jupiter.params.ParameterizedTest;
 import org.junit.jupiter.params.provider.Arguments;
 import org.junit.jupiter.params.provider.MethodSource;
@@ -54,8 +49,6 @@ import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
-@ExtendWith(AutoMockExtension.class)
-@StaticMockSettings(ProxyContext.class)
 class LockClusterExecutorTest {
     
     private final LockClusterExecutor executor = (LockClusterExecutor) 
TypedSPILoader.getService(DistSQLUpdateExecutor.class, 
LockClusterStatement.class);
@@ -74,16 +67,12 @@ class LockClusterExecutorTest {
     @MethodSource("provideOperationScenarios")
     void assertExecuteUpdateWithOperationScenarios(final String name, final 
LockClusterStatement sqlStatement,
                                                    final long 
expectedTimeoutMillis, final ShardingSphereState callbackState,
-                                                   final Class<? extends 
Throwable> expectedException, final boolean expectStateUpdated) throws 
SQLException {
+                                                   final Class<? extends 
Throwable> expectedException, final ShardingSphereState expectedState) throws 
SQLException {
         ContextManager contextManager = mock(ContextManager.class, 
RETURNS_DEEP_STUBS);
         ExclusiveOperatorEngine exclusiveOperatorEngine = 
mock(ExclusiveOperatorEngine.class);
         
when(contextManager.getExclusiveOperatorEngine()).thenReturn(exclusiveOperatorEngine);
         
when(contextManager.getStateContext().getState()).thenReturn(ShardingSphereState.OK,
 callbackState);
-        StatePersistService stateService = null;
-        if (expectStateUpdated) {
-            stateService = mock(StatePersistService.class);
-            mockStateService(stateService);
-        }
+        StatePersistService stateService = 
contextManager.getPersistServiceFacade().getStateService();
         doAnswer(invocation -> {
             ExclusiveOperationVoidCallback callback = 
invocation.getArgument(2);
             callback.execute();
@@ -95,23 +84,19 @@ class LockClusterExecutorTest {
             assertThrows(expectedException, () -> 
executor.executeUpdate(sqlStatement, contextManager));
         }
         verify(exclusiveOperatorEngine).operate(any(), 
eq(expectedTimeoutMillis), any(ExclusiveOperationVoidCallback.class));
-        if (expectStateUpdated) {
-            verify(stateService).update(ShardingSphereState.READ_ONLY);
+        if (null == expectedState) {
+            verify(stateService, never()).update(any());
+        } else {
+            verify(stateService).update(expectedState);
         }
     }
     
-    private void mockStateService(final StatePersistService stateService) {
-        ProxyContext proxyContext = mock(ProxyContext.class);
-        ContextManager contextManager = mock(ContextManager.class, 
RETURNS_DEEP_STUBS);
-        when(proxyContext.getContextManager()).thenReturn(contextManager);
-        
when(contextManager.getPersistServiceFacade().getStateService()).thenReturn(stateService);
-        when(ProxyContext.getInstance()).thenReturn(proxyContext);
-    }
-    
     private static Stream<Arguments> provideFailureScenarios() {
         return Stream.of(
                 Arguments.of("cluster state is unavailable", new 
LockClusterStatement(new AlgorithmSegment("WRITE", new Properties()), 2000L),
                         ShardingSphereState.UNAVAILABLE, 
LockedClusterException.class),
+                Arguments.of("cluster state is read only", new 
LockClusterStatement(new AlgorithmSegment("WRITE", new Properties()), 2000L),
+                        ShardingSphereState.READ_ONLY, 
LockedClusterException.class),
                 Arguments.of("lock strategy is required", new 
LockClusterStatement(null, 2000L), ShardingSphereState.OK, 
MissingRequiredAlgorithmException.class),
                 Arguments.of("lock strategy is unsupported", new 
LockClusterStatement(new AlgorithmSegment("FOO", new Properties()), 2000L),
                         ShardingSphereState.OK, 
ServiceProviderNotFoundException.class));
@@ -120,10 +105,14 @@ class LockClusterExecutorTest {
     private static Stream<Arguments> provideOperationScenarios() {
         return Stream.of(
                 Arguments.of("use explicit timeout", new 
LockClusterStatement(new AlgorithmSegment("WRITE", new Properties()), 2000L),
-                        2000L, ShardingSphereState.OK, null, true),
+                        2000L, ShardingSphereState.OK, null, 
ShardingSphereState.READ_ONLY),
                 Arguments.of("use default timeout when absent", new 
LockClusterStatement(new AlgorithmSegment("WRITE", new Properties())),
-                        3000L, ShardingSphereState.OK, null, true),
+                        3000L, ShardingSphereState.OK, null, 
ShardingSphereState.READ_ONLY),
+                Arguments.of("lock reads and writes", new 
LockClusterStatement(new AlgorithmSegment("READ_WRITE", new Properties()), 
2000L),
+                        2000L, ShardingSphereState.OK, null, 
ShardingSphereState.UNAVAILABLE),
                 Arguments.of("throw exception when callback state changes", 
new LockClusterStatement(new AlgorithmSegment("WRITE", new Properties()), 
2000L),
-                        2000L, ShardingSphereState.UNAVAILABLE, 
LockedClusterException.class, false));
+                        2000L, ShardingSphereState.UNAVAILABLE, 
LockedClusterException.class, null),
+                Arguments.of("throw exception when callback state becomes read 
only", new LockClusterStatement(new AlgorithmSegment("WRITE", new 
Properties()), 2000L),
+                        2000L, ShardingSphereState.READ_ONLY, 
LockedClusterException.class, null));
     }
 }
diff --git 
a/jdbc/src/test/java/org/apache/shardingsphere/driver/jdbc/core/statement/DistSQLStatementExecutorTest.java
 
b/jdbc/src/test/java/org/apache/shardingsphere/driver/jdbc/core/statement/DistSQLStatementExecutorTest.java
index 3544456d3b4..b9b61e965a1 100644
--- 
a/jdbc/src/test/java/org/apache/shardingsphere/driver/jdbc/core/statement/DistSQLStatementExecutorTest.java
+++ 
b/jdbc/src/test/java/org/apache/shardingsphere/driver/jdbc/core/statement/DistSQLStatementExecutorTest.java
@@ -20,28 +20,43 @@ package 
org.apache.shardingsphere.driver.jdbc.core.statement;
 import 
org.apache.shardingsphere.distsql.handler.engine.DistSQLConnectionContext;
 import 
org.apache.shardingsphere.distsql.handler.engine.query.DistSQLQueryExecuteEngine;
 import 
org.apache.shardingsphere.distsql.handler.engine.update.DistSQLUpdateExecuteEngine;
+import org.apache.shardingsphere.distsql.segment.AlgorithmSegment;
 import org.apache.shardingsphere.distsql.statement.DistSQLStatement;
+import 
org.apache.shardingsphere.distsql.statement.type.ral.updatable.LockClusterStatement;
 import 
org.apache.shardingsphere.distsql.statement.type.rdl.resource.unit.type.UnregisterStorageUnitStatement;
 import org.apache.shardingsphere.distsql.statement.type.rul.sql.ParseStatement;
 import 
org.apache.shardingsphere.driver.jdbc.core.connection.ShardingSphereConnection;
 import 
org.apache.shardingsphere.infra.exception.generic.UnsupportedSQLOperationException;
 import 
org.apache.shardingsphere.infra.merge.result.impl.local.LocalDataQueryResultRow;
 import org.apache.shardingsphere.infra.session.query.QueryContext;
+import org.apache.shardingsphere.mode.exclusive.ExclusiveOperatorEngine;
+import 
org.apache.shardingsphere.mode.exclusive.callback.ExclusiveOperationVoidCallback;
+import org.apache.shardingsphere.mode.manager.ContextManager;
+import org.apache.shardingsphere.mode.state.ShardingSphereState;
 import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
 import org.mockito.MockedConstruction;
 
 import java.sql.ResultSet;
 import java.sql.SQLException;
 import java.sql.Statement;
 import java.util.Collections;
+import java.util.Properties;
 import java.util.concurrent.atomic.AtomicReference;
+import java.util.stream.Stream;
 
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.hamcrest.Matchers.is;
 import static org.hamcrest.Matchers.sameInstance;
 import static org.junit.jupiter.api.Assertions.assertThrows;
 import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.RETURNS_DEEP_STUBS;
+import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.mockConstruction;
 import static org.mockito.Mockito.verify;
@@ -83,6 +98,32 @@ class DistSQLStatementExecutorTest {
         }
     }
     
+    @ParameterizedTest(name = "{0}")
+    @MethodSource("provideLockClusterStatements")
+    void assertExecuteUpdateWithLockCluster(final String name, final 
LockClusterStatement sqlStatement,
+                                            final long expectedTimeoutMillis, 
final ShardingSphereState expectedState) throws SQLException {
+        ShardingSphereConnection connection = 
mock(ShardingSphereConnection.class, RETURNS_DEEP_STUBS);
+        ContextManager contextManager = connection.getContextManager();
+        
when(contextManager.getComputeNodeInstanceContext().getModeConfiguration().isCluster()).thenReturn(true);
+        
when(contextManager.getStateContext().getState()).thenReturn(ShardingSphereState.OK);
+        ExclusiveOperatorEngine exclusiveOperatorEngine = 
contextManager.getExclusiveOperatorEngine();
+        doAnswer(invocation -> {
+            ExclusiveOperationVoidCallback callback = 
invocation.getArgument(2);
+            callback.execute();
+            return null;
+        }).when(exclusiveOperatorEngine).operate(any(), anyLong(), 
any(ExclusiveOperationVoidCallback.class));
+        new DistSQLStatementExecutor(connection, mock(StatementManager.class), 
mock(Statement.class)).executeUpdate(createQueryContext(sqlStatement));
+        verify(exclusiveOperatorEngine).operate(any(), 
eq(expectedTimeoutMillis), any(ExclusiveOperationVoidCallback.class));
+        
verify(contextManager.getPersistServiceFacade().getStateService()).update(expectedState);
+    }
+    
+    private static Stream<Arguments> provideLockClusterStatements() {
+        return Stream.of(
+                Arguments.of("write lock with explicit timeout", new 
LockClusterStatement(new AlgorithmSegment("WRITE", new Properties()), 2000L), 
2000L, ShardingSphereState.READ_ONLY),
+                Arguments.of("write lock with default timeout", new 
LockClusterStatement(new AlgorithmSegment("WRITE", new Properties())), 3000L, 
ShardingSphereState.READ_ONLY),
+                Arguments.of("read-write lock with explicit timeout", new 
LockClusterStatement(new AlgorithmSegment("READ_WRITE", new Properties()), 
2000L), 2000L, ShardingSphereState.UNAVAILABLE));
+    }
+    
     @Test
     void assertIsQuery() {
         QueryContext queryContext = 
createQueryContext(mock(DistSQLStatement.class));
diff --git 
a/mode/type/cluster/core/src/main/java/org/apache/shardingsphere/mode/manager/cluster/lock/spi/ClusterLockStrategy.java
 
b/mode/type/cluster/core/src/main/java/org/apache/shardingsphere/mode/manager/cluster/lock/spi/ClusterLockStrategy.java
index 9fa4448f58e..404489fcd6b 100644
--- 
a/mode/type/cluster/core/src/main/java/org/apache/shardingsphere/mode/manager/cluster/lock/spi/ClusterLockStrategy.java
+++ 
b/mode/type/cluster/core/src/main/java/org/apache/shardingsphere/mode/manager/cluster/lock/spi/ClusterLockStrategy.java
@@ -19,6 +19,7 @@ package 
org.apache.shardingsphere.mode.manager.cluster.lock.spi;
 
 import org.apache.shardingsphere.infra.spi.annotation.SingletonSPI;
 import org.apache.shardingsphere.infra.spi.type.typed.TypedSPI;
+import org.apache.shardingsphere.mode.manager.ContextManager;
 
 /**
  * Cluster lock strategy.
@@ -27,7 +28,10 @@ import 
org.apache.shardingsphere.infra.spi.type.typed.TypedSPI;
 public interface ClusterLockStrategy extends TypedSPI {
     
     /**
-     * Lock cluster.
+     * Lock the cluster associated with the caller's context manager.
+     * Implementations must not retain the context manager because strategies 
are shared singletons.
+     *
+     * @param contextManager caller's context manager
      */
-    void lock();
+    void lock(ContextManager contextManager);
 }
diff --git 
a/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/handler/distsql/DistSQLUpdateProxyBackendHandlerTest.java
 
b/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/handler/distsql/DistSQLUpdateProxyBackendHandlerTest.java
index 99cef91eb04..c097e70499b 100644
--- 
a/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/handler/distsql/DistSQLUpdateProxyBackendHandlerTest.java
+++ 
b/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/handler/distsql/DistSQLUpdateProxyBackendHandlerTest.java
@@ -18,6 +18,8 @@
 package org.apache.shardingsphere.proxy.backend.handler.distsql;
 
 import org.apache.shardingsphere.database.connector.core.type.DatabaseType;
+import org.apache.shardingsphere.distsql.segment.AlgorithmSegment;
+import 
org.apache.shardingsphere.distsql.statement.type.ral.updatable.LockClusterStatement;
 import 
org.apache.shardingsphere.distsql.statement.type.ral.updatable.RefreshTableMetaDataStatement;
 import org.apache.shardingsphere.infra.config.props.ConfigurationProperties;
 import 
org.apache.shardingsphere.infra.exception.kernel.metadata.SchemaNotFoundException;
@@ -31,12 +33,18 @@ import 
org.apache.shardingsphere.infra.metadata.database.rule.RuleMetaData;
 import 
org.apache.shardingsphere.infra.metadata.database.schema.model.ShardingSphereSchema;
 import org.apache.shardingsphere.infra.session.query.QueryContext;
 import org.apache.shardingsphere.infra.spi.type.typed.TypedSPILoader;
+import org.apache.shardingsphere.mode.exclusive.ExclusiveOperatorEngine;
+import 
org.apache.shardingsphere.mode.exclusive.callback.ExclusiveOperationVoidCallback;
 import org.apache.shardingsphere.mode.manager.ContextManager;
+import org.apache.shardingsphere.mode.state.ShardingSphereState;
 import 
org.apache.shardingsphere.proxy.backend.response.header.update.UpdateResponseHeader;
 import org.apache.shardingsphere.proxy.backend.session.ConnectionSession;
 import 
org.apache.shardingsphere.sql.parser.statement.core.value.identifier.IdentifierValue;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.extension.ExtendWith;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
 import org.mockito.Answers;
 import org.mockito.Mock;
 import org.mockito.junit.jupiter.MockitoExtension;
@@ -44,13 +52,18 @@ import org.mockito.junit.jupiter.MockitoExtension;
 import java.sql.SQLException;
 import java.util.Collections;
 import java.util.Properties;
+import java.util.stream.Stream;
 
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.hamcrest.Matchers.isA;
 import static org.junit.jupiter.api.Assertions.assertThrows;
 import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.RETURNS_DEEP_STUBS;
+import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
 @ExtendWith(MockitoExtension.class)
@@ -130,6 +143,30 @@ class DistSQLUpdateProxyBackendHandlerTest {
         assertThat(new DistSQLUpdateProxyBackendHandler(sqlStatement, 
mockQueryContext(), mockConnectionSession(), contextManager).execute(), 
isA(UpdateResponseHeader.class));
     }
     
+    @ParameterizedTest(name = "{0}")
+    @MethodSource("provideLockClusterStatements")
+    void assertUpdateWithLockCluster(final String name, final 
LockClusterStatement sqlStatement,
+                                     final long expectedTimeoutMillis, final 
ShardingSphereState expectedState) throws SQLException {
+        
when(contextManager.getComputeNodeInstanceContext().getModeConfiguration().isCluster()).thenReturn(true);
+        
when(contextManager.getStateContext().getState()).thenReturn(ShardingSphereState.OK);
+        ExclusiveOperatorEngine exclusiveOperatorEngine = 
contextManager.getExclusiveOperatorEngine();
+        doAnswer(invocation -> {
+            ExclusiveOperationVoidCallback callback = 
invocation.getArgument(2);
+            callback.execute();
+            return null;
+        }).when(exclusiveOperatorEngine).operate(any(), anyLong(), 
any(ExclusiveOperationVoidCallback.class));
+        assertThat(new DistSQLUpdateProxyBackendHandler(sqlStatement, 
mockQueryContext(), mockConnectionSession(), contextManager).execute(), 
isA(UpdateResponseHeader.class));
+        verify(exclusiveOperatorEngine).operate(any(), 
eq(expectedTimeoutMillis), any(ExclusiveOperationVoidCallback.class));
+        
verify(contextManager.getPersistServiceFacade().getStateService()).update(expectedState);
+    }
+    
+    private static Stream<Arguments> provideLockClusterStatements() {
+        return Stream.of(
+                Arguments.of("write lock with explicit timeout", new 
LockClusterStatement(new AlgorithmSegment("WRITE", new Properties()), 2000L), 
2000L, ShardingSphereState.READ_ONLY),
+                Arguments.of("write lock with default timeout", new 
LockClusterStatement(new AlgorithmSegment("WRITE", new Properties())), 3000L, 
ShardingSphereState.READ_ONLY),
+                Arguments.of("read-write lock with explicit timeout", new 
LockClusterStatement(new AlgorithmSegment("READ_WRITE", new Properties()), 
2000L), 2000L, ShardingSphereState.UNAVAILABLE));
+    }
+    
     private QueryContext mockQueryContext() {
         return mock(QueryContext.class, RETURNS_DEEP_STUBS);
     }

Reply via email to