This is an automated email from the ASF dual-hosted git repository.
RaigorJiang 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 7a75e3931f6 Reset proxy backend executor across repeated
ShardingSphereProxy lifecycles (#38665)
7a75e3931f6 is described below
commit 7a75e3931f6d404af7ee299c0112d997a0e22230
Author: Hengqian Ling <[email protected]>
AuthorDate: Sat May 9 10:11:18 2026 +0800
Reset proxy backend executor across repeated ShardingSphereProxy lifecycles
(#38665)
* Reset proxy backend executor across repeated ShardingSphereProxy
lifecycles
* Introducing the Lifecycle
---
.../backend/context/BackendExecutorContext.java | 66 ++++++++++++++++++++--
.../context/BackendExecutorContextTest.java | 47 ++++++++++++++-
.../proxy/initializer/BootstrapInitializer.java | 2 +
.../initializer/BootstrapInitializerTest.java | 23 +++++++-
.../proxy/frontend/ShardingSphereProxy.java | 2 +-
5 files changed, 131 insertions(+), 9 deletions(-)
diff --git
a/proxy/backend/core/src/main/java/org/apache/shardingsphere/proxy/backend/context/BackendExecutorContext.java
b/proxy/backend/core/src/main/java/org/apache/shardingsphere/proxy/backend/context/BackendExecutorContext.java
index d05ffb2c904..10578a8c85d 100644
---
a/proxy/backend/core/src/main/java/org/apache/shardingsphere/proxy/backend/context/BackendExecutorContext.java
+++
b/proxy/backend/core/src/main/java/org/apache/shardingsphere/proxy/backend/context/BackendExecutorContext.java
@@ -18,7 +18,6 @@
package org.apache.shardingsphere.proxy.backend.context;
import lombok.AccessLevel;
-import lombok.Getter;
import lombok.NoArgsConstructor;
import org.apache.shardingsphere.infra.config.props.ConfigurationPropertyKey;
import org.apache.shardingsphere.infra.executor.kernel.ExecutorEngine;
@@ -27,13 +26,13 @@ import
org.apache.shardingsphere.infra.executor.kernel.ExecutorEngine;
* Backend executor context.
*/
@NoArgsConstructor(access = AccessLevel.PRIVATE)
-@Getter
public final class BackendExecutorContext {
private static final BackendExecutorContext INSTANCE = new
BackendExecutorContext();
- private final ExecutorEngine executorEngine =
ExecutorEngine.createExecutorEngineWithSize(
-
ProxyContext.getInstance().getContextManager().getMetaDataContexts().getMetaData().getProps().<Integer>getValue(ConfigurationPropertyKey.KERNEL_EXECUTOR_SIZE));
+ private volatile ExecutorEngine executorEngine;
+
+ private LifecycleState lifecycleState = LifecycleState.UNINITIALIZED;
/**
* Get executor context instance.
@@ -43,4 +42,63 @@ public final class BackendExecutorContext {
public static BackendExecutorContext getInstance() {
return INSTANCE;
}
+
+ /**
+ * Initialize backend executor context.
+ */
+ public synchronized void init() {
+ if (null != executorEngine) {
+ executorEngine.close();
+ }
+ executorEngine = ExecutorEngine.createExecutorEngineWithSize(
+
ProxyContext.getInstance().getContextManager().getMetaDataContexts().getMetaData().getProps().<Integer>getValue(ConfigurationPropertyKey.KERNEL_EXECUTOR_SIZE));
+ lifecycleState = LifecycleState.RUNNING;
+ }
+
+ /**
+ * Get executor engine.
+ *
+ * @return executor engine
+ * @throws IllegalStateException backend executor is unavailable in
current lifecycle state
+ */
+ public synchronized ExecutorEngine getExecutorEngine() {
+ if (null == executorEngine) {
+ if (LifecycleState.CLOSED == lifecycleState) {
+ throw new IllegalStateException(String.format("Backend
executor engine is unavailable in `%s` lifecycle state.", lifecycleState));
+ }
+ init();
+ }
+ if (LifecycleState.RUNNING != lifecycleState) {
+ throw new IllegalStateException(String.format("Backend executor
engine is unavailable in `%s` lifecycle state.", lifecycleState));
+ }
+ return executorEngine;
+ }
+
+ /**
+ * Close backend executor context.
+ */
+ public synchronized void close() {
+ if (null != executorEngine) {
+ executorEngine.close();
+ executorEngine = null;
+ }
+ lifecycleState = LifecycleState.UNINITIALIZED;
+ }
+
+ /**
+ * Shutdown backend executor context.
+ */
+ public synchronized void shutdown() {
+ close();
+ lifecycleState = LifecycleState.CLOSED;
+ }
+
+ private enum LifecycleState {
+
+ UNINITIALIZED,
+
+ RUNNING,
+
+ CLOSED
+ }
}
diff --git
a/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/context/BackendExecutorContextTest.java
b/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/context/BackendExecutorContextTest.java
index b11d9e0e697..614b482e181 100644
---
a/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/context/BackendExecutorContextTest.java
+++
b/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/context/BackendExecutorContextTest.java
@@ -18,6 +18,7 @@
package org.apache.shardingsphere.proxy.backend.context;
import org.apache.shardingsphere.infra.config.props.ConfigurationProperties;
+import org.apache.shardingsphere.infra.executor.kernel.ExecutorEngine;
import org.apache.shardingsphere.infra.metadata.ShardingSphereMetaData;
import
org.apache.shardingsphere.infra.metadata.database.resource.ResourceMetaData;
import org.apache.shardingsphere.infra.metadata.database.rule.RuleMetaData;
@@ -26,14 +27,17 @@ import
org.apache.shardingsphere.mode.manager.ContextManager;
import org.apache.shardingsphere.mode.metadata.MetaDataContexts;
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.AfterEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import java.util.Collections;
import java.util.Properties;
-import static org.hamcrest.Matchers.is;
import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.not;
+import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.Mockito.RETURNS_DEEP_STUBS;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
@@ -42,11 +46,48 @@ import static org.mockito.Mockito.when;
@StaticMockSettings(ProxyContext.class)
class BackendExecutorContextTest {
+ @AfterEach
+ void tearDown() {
+ BackendExecutorContext.getInstance().close();
+ }
+
+ @Test
+ void assertGetExecutorEngine() {
+ ContextManager contextManager = mockContextManager();
+
when(ProxyContext.getInstance().getContextManager()).thenReturn(contextManager);
+ BackendExecutorContext.getInstance().init();
+ ExecutorEngine actual =
BackendExecutorContext.getInstance().getExecutorEngine();
+ assertThat(actual,
is(BackendExecutorContext.getInstance().getExecutorEngine()));
+ }
+
+ @Test
+ void assertInit() {
+ ContextManager contextManager = mockContextManager();
+
when(ProxyContext.getInstance().getContextManager()).thenReturn(contextManager);
+ BackendExecutorContext.getInstance().init();
+ ExecutorEngine actual =
BackendExecutorContext.getInstance().getExecutorEngine();
+ BackendExecutorContext.getInstance().close();
+ BackendExecutorContext.getInstance().init();
+ assertThat(BackendExecutorContext.getInstance().getExecutorEngine(),
is(not(actual)));
+ }
+
+ @Test
+ void assertClose() {
+ ContextManager contextManager = mockContextManager();
+
when(ProxyContext.getInstance().getContextManager()).thenReturn(contextManager);
+ BackendExecutorContext.getInstance().init();
+ BackendExecutorContext.getInstance().close();
+ ExecutorEngine actual =
BackendExecutorContext.getInstance().getExecutorEngine();
+ assertThat(actual,
is(BackendExecutorContext.getInstance().getExecutorEngine()));
+ }
+
@Test
- void assertGetInstance() {
+ void assertShutdown() {
ContextManager contextManager = mockContextManager();
when(ProxyContext.getInstance().getContextManager()).thenReturn(contextManager);
- assertThat(BackendExecutorContext.getInstance().getExecutorEngine(),
is(BackendExecutorContext.getInstance().getExecutorEngine()));
+ BackendExecutorContext.getInstance().init();
+ BackendExecutorContext.getInstance().shutdown();
+ assertThrows(IllegalStateException.class, () ->
BackendExecutorContext.getInstance().getExecutorEngine());
}
private ContextManager mockContextManager() {
diff --git
a/proxy/bootstrap/src/main/java/org/apache/shardingsphere/proxy/initializer/BootstrapInitializer.java
b/proxy/bootstrap/src/main/java/org/apache/shardingsphere/proxy/initializer/BootstrapInitializer.java
index 83d0892362c..7567cc43e5e 100644
---
a/proxy/bootstrap/src/main/java/org/apache/shardingsphere/proxy/initializer/BootstrapInitializer.java
+++
b/proxy/bootstrap/src/main/java/org/apache/shardingsphere/proxy/initializer/BootstrapInitializer.java
@@ -29,6 +29,7 @@ import
org.apache.shardingsphere.mode.manager.builder.ContextManagerBuilderParam
import org.apache.shardingsphere.proxy.backend.config.ProxyConfiguration;
import org.apache.shardingsphere.proxy.backend.config.YamlProxyConfiguration;
import
org.apache.shardingsphere.proxy.backend.config.yaml.swapper.YamlProxyConfigurationSwapper;
+import org.apache.shardingsphere.proxy.backend.context.BackendExecutorContext;
import org.apache.shardingsphere.proxy.backend.context.ProxyContext;
import org.apache.shardingsphere.proxy.version.ShardingSphereProxyVersion;
@@ -51,6 +52,7 @@ public final class BootstrapInitializer {
ProxyConfiguration proxyConfig = new
YamlProxyConfigurationSwapper().swap(yamlConfig);
ContextManager contextManager = createContextManager(proxyConfig,
modeConfig, port);
ProxyContext.init(contextManager);
+ BackendExecutorContext.getInstance().init();
ShardingSphereProxyVersion.setVersion(contextManager);
}
diff --git
a/proxy/bootstrap/src/test/java/org/apache/shardingsphere/proxy/initializer/BootstrapInitializerTest.java
b/proxy/bootstrap/src/test/java/org/apache/shardingsphere/proxy/initializer/BootstrapInitializerTest.java
index 97992487b7d..cb0435a514c 100644
---
a/proxy/bootstrap/src/test/java/org/apache/shardingsphere/proxy/initializer/BootstrapInitializerTest.java
+++
b/proxy/bootstrap/src/test/java/org/apache/shardingsphere/proxy/initializer/BootstrapInitializerTest.java
@@ -28,6 +28,7 @@ import
org.apache.shardingsphere.mode.manager.builder.ContextManagerBuilderParam
import org.apache.shardingsphere.proxy.backend.config.YamlProxyConfiguration;
import
org.apache.shardingsphere.proxy.backend.config.yaml.YamlProxyDatabaseConfiguration;
import
org.apache.shardingsphere.proxy.backend.config.yaml.YamlProxyServerConfiguration;
+import org.apache.shardingsphere.proxy.backend.context.BackendExecutorContext;
import org.apache.shardingsphere.proxy.backend.context.ProxyContext;
import org.apache.shardingsphere.proxy.version.ShardingSphereProxyVersion;
import
org.apache.shardingsphere.test.infra.framework.extension.mock.AutoMockExtension;
@@ -52,11 +53,12 @@ import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@ExtendWith(AutoMockExtension.class)
-@StaticMockSettings({ProxyContext.class, ShardingSphereProxyVersion.class})
+@StaticMockSettings({BackendExecutorContext.class, ProxyContext.class,
ShardingSphereProxyVersion.class})
class BootstrapInitializerTest {
private final Map<Class<?>, Object> originalRegisteredServices = new
HashMap<>(2, 1F);
@@ -90,6 +92,7 @@ class BootstrapInitializerTest {
ArgumentCaptor<ContextManagerBuilderParameter> paramCaptor =
ArgumentCaptor.forClass(ContextManagerBuilderParameter.class);
verify(instanceMetaDataBuilder).build(3307, "");
verify(contextManagerBuilder).build(paramCaptor.capture(),
any(EventBusContext.class));
+ verify(BackendExecutorContext.getInstance()).init();
ContextManagerBuilderParameter actualParameter =
paramCaptor.getValue();
ModeConfiguration actualModeConfig =
actualParameter.getModeConfiguration();
assertThat(actualModeConfig.getType(), is("Standalone"));
@@ -118,6 +121,7 @@ class BootstrapInitializerTest {
ArgumentCaptor<ContextManagerBuilderParameter> paramCaptor =
ArgumentCaptor.forClass(ContextManagerBuilderParameter.class);
verify(instanceMetaDataBuilder).build(3307, "");
verify(contextManagerBuilder).build(paramCaptor.capture(),
any(EventBusContext.class));
+ verify(BackendExecutorContext.getInstance()).init();
ContextManagerBuilderParameter actualParameter =
paramCaptor.getValue();
assertThat(actualParameter.getModeConfiguration().getType(),
is("Cluster"));
assertThat(actualParameter.getDatabaseConfigs().size(), is(1));
@@ -128,6 +132,23 @@ class BootstrapInitializerTest {
assertThat(actualParameter.getInstanceMetaData(),
is(instanceMetaData));
}
+ @Test
+ void assertInitWithRepeatedLifecycle() throws SQLException,
ReflectiveOperationException {
+ InstanceMetaDataBuilder instanceMetaDataBuilder =
mock(InstanceMetaDataBuilder.class);
+ InstanceMetaData instanceMetaData = mock(InstanceMetaData.class);
+ registerSingletonService(InstanceMetaDataBuilder.class,
instanceMetaDataBuilder);
+ ContextManagerBuilder contextManagerBuilder =
mock(ContextManagerBuilder.class);
+ when(instanceMetaDataBuilder.getType()).thenReturn("Proxy");
+ when(instanceMetaDataBuilder.build(3307,
"")).thenReturn(instanceMetaData);
+ when(contextManagerBuilder.isDefault()).thenReturn(true);
+ registerSingletonService(ContextManagerBuilder.class,
contextManagerBuilder);
+ BootstrapInitializer bootstrapInitializer = new BootstrapInitializer();
+ bootstrapInitializer.init(createYamlProxyConfiguration(null), 3307);
+ BackendExecutorContext.getInstance().shutdown();
+ bootstrapInitializer.init(createYamlProxyConfiguration(null), 3307);
+ verify(BackendExecutorContext.getInstance(), times(2)).init();
+ }
+
private YamlProxyConfiguration createYamlProxyConfiguration(final
YamlModeConfiguration modeConfig) {
YamlProxyServerConfiguration serverConfig = new
YamlProxyServerConfiguration();
serverConfig.setMode(modeConfig);
diff --git
a/proxy/frontend/core/src/main/java/org/apache/shardingsphere/proxy/frontend/ShardingSphereProxy.java
b/proxy/frontend/core/src/main/java/org/apache/shardingsphere/proxy/frontend/ShardingSphereProxy.java
index 0a10fc23060..0cfe853c5b1 100644
---
a/proxy/frontend/core/src/main/java/org/apache/shardingsphere/proxy/frontend/ShardingSphereProxy.java
+++
b/proxy/frontend/core/src/main/java/org/apache/shardingsphere/proxy/frontend/ShardingSphereProxy.java
@@ -168,7 +168,7 @@ public final class ShardingSphereProxy {
}
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
- BackendExecutorContext.getInstance().getExecutorEngine().close();
+ BackendExecutorContext.getInstance().shutdown();
ProxyContext.getInstance().getContextManager().close();
isClosed = true;
}