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 d9e2030132f Fix Proxy backend executor lifecycle after repeated
startup and shutdown (#38680)
d9e2030132f is described below
commit d9e2030132fdcd7b33a4e0cb687ed2ad39e99b3b
Author: Raigor <[email protected]>
AuthorDate: Sat May 9 15:44:11 2026 +0800
Fix Proxy backend executor lifecycle after repeated startup and shutdown
(#38680)
* Fix Proxy backend executor lifecycle after repeated startup and shutdown
* Fix test cases
---
.../backend/context/BackendExecutorContext.java | 27 +++++++-------
.../DatabaseProxyConnectorFactoryTest.java | 18 +++++++--
.../backend/connector/ProxySQLExecutorTest.java | 8 ++++
.../StandardDatabaseProxyConnectorTest.java | 8 ++++
.../context/BackendExecutorContextTest.java | 15 ++++----
.../handler/distsql/rul/PreviewExecutorTest.java | 8 ++++
.../initializer/BootstrapInitializerTest.java | 2 +-
...ySQLMultiStatementsProxyBackendHandlerTest.java | 32 ++++++++++++++--
.../PostgreSQLBatchedStatementsExecutorTest.java | 43 ++++++++++++++++++++--
9 files changed, 129 insertions(+), 32 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 10578a8c85d..f975423e905 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
@@ -45,11 +45,12 @@ public final class BackendExecutorContext {
/**
* Initialize backend executor context.
+ *
+ * <p>The proxy bootstrap lifecycle uses this method to create a fresh
backend executor.
+ * It may explicitly restore the context from the closed state for
repeated proxy lifecycles in the same JVM.</p>
*/
public synchronized void init() {
- if (null != executorEngine) {
- executorEngine.close();
- }
+ closeExecutorEngine();
executorEngine = ExecutorEngine.createExecutorEngineWithSize(
ProxyContext.getInstance().getContextManager().getMetaDataContexts().getMetaData().getProps().<Integer>getValue(ConfigurationPropertyKey.KERNEL_EXECUTOR_SIZE));
lifecycleState = LifecycleState.RUNNING;
@@ -75,22 +76,20 @@ public final class BackendExecutorContext {
}
/**
- * Close backend executor context.
+ * Shutdown backend executor context.
+ *
+ * <p>After shutdown, request-side executor lookup is rejected until the
next explicit lifecycle initialization.</p>
*/
- public synchronized void close() {
+ public synchronized void shutdown() {
+ closeExecutorEngine();
+ lifecycleState = LifecycleState.CLOSED;
+ }
+
+ private void closeExecutorEngine() {
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 {
diff --git
a/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/connector/DatabaseProxyConnectorFactoryTest.java
b/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/connector/DatabaseProxyConnectorFactoryTest.java
index 13f2545d422..f9d79eee5ea 100644
---
a/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/connector/DatabaseProxyConnectorFactoryTest.java
+++
b/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/connector/DatabaseProxyConnectorFactoryTest.java
@@ -33,9 +33,11 @@ import
org.apache.shardingsphere.infra.session.query.QueryContext;
import org.apache.shardingsphere.infra.spi.type.typed.TypedSPILoader;
import org.apache.shardingsphere.mode.manager.ContextManager;
import org.apache.shardingsphere.mode.metadata.MetaDataContexts;
+import org.apache.shardingsphere.proxy.backend.context.BackendExecutorContext;
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.AfterEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.jupiter.params.ParameterizedTest;
@@ -62,6 +64,11 @@ class DatabaseProxyConnectorFactoryTest {
private final DatabaseType databaseType =
TypedSPILoader.getService(DatabaseType.class, "FIXTURE");
+ @AfterEach
+ void tearDown() {
+ BackendExecutorContext.getInstance().shutdown();
+ }
+
@Test
void assertNewDatabaseProxyConnectorWithoutParameter() {
ProxyDatabaseConnectionManager databaseConnectionManager =
mock(ProxyDatabaseConnectionManager.class, RETURNS_DEEP_STUBS);
@@ -75,7 +82,7 @@ class DatabaseProxyConnectorFactoryTest {
when(metaData.getDatabase("foo_db")).thenReturn(database);
QueryContext queryContext = new QueryContext(sqlStatementContext,
"schemaName", Collections.emptyList(), new HintValueContext(),
mockConnectionContext(), metaData);
ContextManager contextManager = mockContextManager(database);
-
when(ProxyContext.getInstance().getContextManager()).thenReturn(contextManager);
+ initBackendExecutorContext(contextManager);
DatabaseProxyConnector engine =
DatabaseProxyConnectorFactory.newInstance(queryContext,
databaseConnectionManager, false);
assertThat(engine, isA(DatabaseProxyConnector.class));
}
@@ -98,7 +105,7 @@ class DatabaseProxyConnectorFactoryTest {
when(metaData.containsDatabase("foo_db")).thenReturn(true);
when(metaData.getDatabase("foo_db")).thenReturn(database);
ContextManager contextManager = mockContextManager(database);
-
when(ProxyContext.getInstance().getContextManager()).thenReturn(contextManager);
+ initBackendExecutorContext(contextManager);
assertThat(DatabaseProxyConnectorFactory.newInstance(
new QueryContext(sqlStatementContext, "schemaName",
Collections.emptyList(), new HintValueContext(), mockConnectionContext(),
metaData), databaseConnectionManager, false),
isA(DatabaseProxyConnector.class));
@@ -116,11 +123,16 @@ class DatabaseProxyConnectorFactoryTest {
ShardingSphereMetaData metaData = new
ShardingSphereMetaData(Collections.singleton(database), mock(), mock(), new
ConfigurationProperties(new Properties()));
QueryContext queryContext = new QueryContext(sqlStatementContext,
"schemaName", parameters, new HintValueContext(), mockConnectionContext(),
metaData);
ContextManager contextManager = mockContextManager(database);
-
when(ProxyContext.getInstance().getContextManager()).thenReturn(contextManager);
+ initBackendExecutorContext(contextManager);
DatabaseProxyConnector connector =
DatabaseProxyConnectorFactory.newInstance(queryContext,
databaseConnectionManager, preferPreparedStatement);
assertThat((JDBCDriverType)
Plugins.getMemberAccessor().get(connector.getClass().getDeclaredField("driverType"),
connector), is(expected));
}
+ private void initBackendExecutorContext(final ContextManager
contextManager) {
+
when(ProxyContext.getInstance().getContextManager()).thenReturn(contextManager);
+ BackendExecutorContext.getInstance().init();
+ }
+
private ContextManager mockContextManager(final ShardingSphereDatabase
database) {
ShardingSphereMetaData metaData = new ShardingSphereMetaData(
Collections.singleton(database), mock(ResourceMetaData.class),
mock(RuleMetaData.class), new ConfigurationProperties(new Properties()));
diff --git
a/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/connector/ProxySQLExecutorTest.java
b/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/connector/ProxySQLExecutorTest.java
index fda908a4efa..898a4a652ea 100644
---
a/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/connector/ProxySQLExecutorTest.java
+++
b/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/connector/ProxySQLExecutorTest.java
@@ -51,6 +51,7 @@ import org.apache.shardingsphere.mode.manager.ContextManager;
import
org.apache.shardingsphere.proxy.backend.connector.jdbc.executor.ProxyJDBCExecutor;
import
org.apache.shardingsphere.proxy.backend.connector.jdbc.statement.JDBCBackendStatement;
import
org.apache.shardingsphere.proxy.backend.connector.sane.DialectSaneQueryResultEngine;
+import org.apache.shardingsphere.proxy.backend.context.BackendExecutorContext;
import org.apache.shardingsphere.proxy.backend.context.ProxyContext;
import org.apache.shardingsphere.proxy.backend.session.ConnectionSession;
import
org.apache.shardingsphere.sql.parser.statement.core.enums.TransactionIsolationLevel;
@@ -71,6 +72,7 @@ import
org.apache.shardingsphere.test.infra.framework.extension.mock.StaticMockS
import org.apache.shardingsphere.transaction.api.TransactionType;
import org.apache.shardingsphere.transaction.rule.TransactionRule;
import org.apache.shardingsphere.transaction.spi.TransactionHook;
+import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInstance;
@@ -185,6 +187,12 @@ class ProxySQLExecutorTest {
when(contextManager.getDatabase("foo_db")).thenReturn(database);
when(contextManager.getDatabaseType()).thenReturn(fixtureDatabaseType);
when(ProxyContext.getInstance().getContextManager()).thenReturn(contextManager);
+ BackendExecutorContext.getInstance().init();
+ }
+
+ @AfterEach
+ void tearDown() {
+ BackendExecutorContext.getInstance().shutdown();
}
@Test
diff --git
a/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/connector/StandardDatabaseProxyConnectorTest.java
b/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/connector/StandardDatabaseProxyConnectorTest.java
index c985fdd6186..4a859280afb 100644
---
a/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/connector/StandardDatabaseProxyConnectorTest.java
+++
b/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/connector/StandardDatabaseProxyConnectorTest.java
@@ -73,6 +73,7 @@ import org.apache.shardingsphere.parser.rule.SQLParserRule;
import
org.apache.shardingsphere.proxy.backend.connector.jdbc.fixture.QueryHeaderBuilderFixture;
import
org.apache.shardingsphere.proxy.backend.connector.jdbc.statement.JDBCBackendStatement;
import
org.apache.shardingsphere.proxy.backend.connector.jdbc.transaction.ProxyBackendTransactionManager;
+import org.apache.shardingsphere.proxy.backend.context.BackendExecutorContext;
import org.apache.shardingsphere.proxy.backend.context.ProxyContext;
import org.apache.shardingsphere.proxy.backend.response.header.ResponseHeader;
import
org.apache.shardingsphere.proxy.backend.response.header.query.QueryHeaderBuilder;
@@ -92,6 +93,7 @@ import
org.apache.shardingsphere.sqlfederation.engine.SQLFederationEngine;
import org.apache.shardingsphere.sqlfederation.rule.SQLFederationRule;
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.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
@@ -160,6 +162,12 @@ class StandardDatabaseProxyConnectorTest {
when(databaseConnectionManager.getConnectionSession().getUsedDatabaseName()).thenReturn("foo_db");
ContextManager contextManager = mockContextManager();
when(ProxyContext.getInstance().getContextManager()).thenReturn(contextManager);
+ BackendExecutorContext.getInstance().init();
+ }
+
+ @AfterEach
+ void tearDown() {
+ BackendExecutorContext.getInstance().shutdown();
}
private ContextManager mockContextManager() {
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 614b482e181..699bbdcf0d3 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
@@ -48,7 +48,7 @@ class BackendExecutorContextTest {
@AfterEach
void tearDown() {
- BackendExecutorContext.getInstance().close();
+ BackendExecutorContext.getInstance().shutdown();
}
@Test
@@ -66,28 +66,29 @@ class BackendExecutorContextTest {
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() {
+ void assertShutdown() {
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()));
+ BackendExecutorContext.getInstance().shutdown();
+ assertThrows(IllegalStateException.class, () ->
BackendExecutorContext.getInstance().getExecutorEngine());
}
@Test
- void assertShutdown() {
+ void assertInitAfterShutdown() {
ContextManager contextManager = mockContextManager();
when(ProxyContext.getInstance().getContextManager()).thenReturn(contextManager);
BackendExecutorContext.getInstance().init();
+ final ExecutorEngine actual =
BackendExecutorContext.getInstance().getExecutorEngine();
BackendExecutorContext.getInstance().shutdown();
assertThrows(IllegalStateException.class, () ->
BackendExecutorContext.getInstance().getExecutorEngine());
+ BackendExecutorContext.getInstance().init();
+ assertThat(BackendExecutorContext.getInstance().getExecutorEngine(),
is(not(actual)));
}
private ContextManager mockContextManager() {
diff --git
a/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/handler/distsql/rul/PreviewExecutorTest.java
b/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/handler/distsql/rul/PreviewExecutorTest.java
index e30a6cb4d72..bd90c43d6d7 100644
---
a/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/handler/distsql/rul/PreviewExecutorTest.java
+++
b/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/handler/distsql/rul/PreviewExecutorTest.java
@@ -58,6 +58,7 @@ import org.apache.shardingsphere.mode.manager.ContextManager;
import org.apache.shardingsphere.parser.rule.SQLParserRule;
import
org.apache.shardingsphere.parser.rule.builder.DefaultSQLParserRuleConfigurationBuilder;
import
org.apache.shardingsphere.proxy.backend.connector.ProxyDatabaseConnectionManager;
+import org.apache.shardingsphere.proxy.backend.context.BackendExecutorContext;
import org.apache.shardingsphere.proxy.backend.context.ProxyContext;
import
org.apache.shardingsphere.sql.parser.statement.core.segment.ddl.cursor.CursorNameSegment;
import
org.apache.shardingsphere.sql.parser.statement.core.statement.SQLStatement;
@@ -66,6 +67,7 @@ import
org.apache.shardingsphere.sql.parser.statement.core.statement.attribute.t
import
org.apache.shardingsphere.sql.parser.statement.core.value.identifier.IdentifierValue;
import org.apache.shardingsphere.sqlfederation.context.SQLFederationContext;
import org.apache.shardingsphere.sqlfederation.engine.SQLFederationEngine;
+import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.MockedConstruction;
@@ -108,6 +110,12 @@ class PreviewExecutorTest {
void setUp() {
contextManager = mockContextManager();
ProxyContext.init(contextManager);
+ BackendExecutorContext.getInstance().init();
+ }
+
+ @AfterEach
+ void tearDown() {
+ BackendExecutorContext.getInstance().shutdown();
}
private ContextManager mockContextManager() {
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 cb0435a514c..317cdfb90ac 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
@@ -133,7 +133,7 @@ class BootstrapInitializerTest {
}
@Test
- void assertInitWithRepeatedLifecycle() throws SQLException,
ReflectiveOperationException {
+ void assertInitWithRepeatedBootstrap() throws SQLException,
ReflectiveOperationException {
InstanceMetaDataBuilder instanceMetaDataBuilder =
mock(InstanceMetaDataBuilder.class);
InstanceMetaData instanceMetaData = mock(InstanceMetaData.class);
registerSingletonService(InstanceMetaDataBuilder.class,
instanceMetaDataBuilder);
diff --git
a/proxy/frontend/dialect/mysql/src/test/java/org/apache/shardingsphere/proxy/frontend/mysql/command/query/text/query/MySQLMultiStatementsProxyBackendHandlerTest.java
b/proxy/frontend/dialect/mysql/src/test/java/org/apache/shardingsphere/proxy/frontend/mysql/command/query/text/query/MySQLMultiStatementsProxyBackendHandlerTest.java
index b83091fffdb..368f6adb579 100644
---
a/proxy/frontend/dialect/mysql/src/test/java/org/apache/shardingsphere/proxy/frontend/mysql/command/query/text/query/MySQLMultiStatementsProxyBackendHandlerTest.java
+++
b/proxy/frontend/dialect/mysql/src/test/java/org/apache/shardingsphere/proxy/frontend/mysql/command/query/text/query/MySQLMultiStatementsProxyBackendHandlerTest.java
@@ -20,6 +20,7 @@ package
org.apache.shardingsphere.proxy.frontend.mysql.command.query.text.query;
import org.apache.shardingsphere.database.connector.core.type.DatabaseType;
import org.apache.shardingsphere.infra.config.props.ConfigurationProperties;
import org.apache.shardingsphere.infra.config.props.ConfigurationPropertyKey;
+import org.apache.shardingsphere.infra.executor.kernel.ExecutorEngine;
import
org.apache.shardingsphere.infra.executor.sql.execute.engine.ConnectionMode;
import
org.apache.shardingsphere.infra.executor.sql.prepare.driver.jdbc.StatementOption;
import
org.apache.shardingsphere.infra.metadata.database.ShardingSphereDatabase;
@@ -35,6 +36,7 @@ import org.apache.shardingsphere.parser.rule.SQLParserRule;
import
org.apache.shardingsphere.parser.rule.builder.DefaultSQLParserRuleConfigurationBuilder;
import
org.apache.shardingsphere.proxy.backend.connector.ProxyDatabaseConnectionManager;
import
org.apache.shardingsphere.proxy.backend.connector.jdbc.statement.JDBCBackendStatement;
+import org.apache.shardingsphere.proxy.backend.context.BackendExecutorContext;
import org.apache.shardingsphere.proxy.backend.context.ProxyContext;
import org.apache.shardingsphere.proxy.backend.response.header.ResponseHeader;
import
org.apache.shardingsphere.proxy.backend.response.header.update.MultiStatementsUpdateResponseHeader;
@@ -63,6 +65,8 @@ import java.util.Properties;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.isA;
+import static org.hamcrest.Matchers.not;
+import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
@@ -82,7 +86,7 @@ class MySQLMultiStatementsProxyBackendHandlerTest {
ConnectionSession connectionSession = mockConnectionSession();
UpdateStatement expectedStatement = mock(UpdateStatement.class);
ContextManager contextManager = mockContextManager();
-
when(ProxyContext.getInstance().getContextManager()).thenReturn(contextManager);
+ initBackendExecutorContext(contextManager);
ResponseHeader actual = new
MySQLMultiStatementsProxyBackendHandler(connectionSession, expectedStatement,
sql).execute();
assertThat(actual, isA(MultiStatementsUpdateResponseHeader.class));
MultiStatementsUpdateResponseHeader actualHeader =
(MultiStatementsUpdateResponseHeader) actual;
@@ -102,13 +106,30 @@ class MySQLMultiStatementsProxyBackendHandlerTest {
assertThat(responseHeader.getSqlStatement(), is(expectedStatement));
}
+ @Test
+ void assertExecuteAfterRepeatedProxyLifecycle() throws SQLException {
+ final String sql = "UPDATE t SET v=v+1 WHERE id=1;UPDATE t SET v=v+1
WHERE id=2;UPDATE t SET v=v+1 WHERE id=3";
+ final ConnectionSession connectionSession = mockConnectionSession();
+ final UpdateStatement expectedStatement = mock(UpdateStatement.class);
+ ContextManager contextManager = mockContextManager();
+ initBackendExecutorContext(contextManager);
+ final ExecutorEngine previousExecutorEngine =
BackendExecutorContext.getInstance().getExecutorEngine();
+ BackendExecutorContext.getInstance().shutdown();
+ assertThrows(IllegalStateException.class, () ->
BackendExecutorContext.getInstance().getExecutorEngine());
+ BackendExecutorContext.getInstance().init();
+ assertThat(BackendExecutorContext.getInstance().getExecutorEngine(),
is(not(previousExecutorEngine)));
+ ResponseHeader actual = new
MySQLMultiStatementsProxyBackendHandler(connectionSession, expectedStatement,
sql).execute();
+ assertThat(actual, isA(MultiStatementsUpdateResponseHeader.class));
+ assertThat(((MultiStatementsUpdateResponseHeader)
actual).getUpdateResponseHeaders().size(), is(3));
+ }
+
@Test
void assertExecuteWithSpecifiedDatabaseName() throws SQLException {
String sql = "UPDATE foo_db.t SET v=v+1 WHERE id=1;UPDATE foo_db.t SET
v=v+1 WHERE id=2;UPDATE foo_db.t SET v=v+1 WHERE id=3";
ConnectionSession connectionSession = mockConnectionSession();
UpdateStatement expectedStatement = mock(UpdateStatement.class);
ContextManager contextManager = mockContextManager();
-
when(ProxyContext.getInstance().getContextManager()).thenReturn(contextManager);
+ initBackendExecutorContext(contextManager);
ResponseHeader actual = new
MySQLMultiStatementsProxyBackendHandler(connectionSession, expectedStatement,
sql).execute();
assertThat(actual, isA(MultiStatementsUpdateResponseHeader.class));
MultiStatementsUpdateResponseHeader actualHeader =
(MultiStatementsUpdateResponseHeader) actual;
@@ -135,7 +156,7 @@ class MySQLMultiStatementsProxyBackendHandlerTest {
ConnectionSession connectionSession = mockConnectionSession();
UpdateStatement expectedStatement = mock(UpdateStatement.class);
ContextManager contextManager = mockContextManager();
-
when(ProxyContext.getInstance().getContextManager()).thenReturn(contextManager);
+ initBackendExecutorContext(contextManager);
ResponseHeader actual = new
MySQLMultiStatementsProxyBackendHandler(connectionSession, expectedStatement,
sql).execute();
assertThat(actual, isA(MultiStatementsUpdateResponseHeader.class));
MultiStatementsUpdateResponseHeader actualHeader =
(MultiStatementsUpdateResponseHeader) actual;
@@ -155,6 +176,11 @@ class MySQLMultiStatementsProxyBackendHandlerTest {
assertThat(responseHeader.getSqlStatement(), is(expectedStatement));
}
+ private void initBackendExecutorContext(final ContextManager
contextManager) {
+
when(ProxyContext.getInstance().getContextManager()).thenReturn(contextManager);
+ BackendExecutorContext.getInstance().init();
+ }
+
private ConnectionSession mockConnectionSession() throws SQLException {
ConnectionSession result = mock(ConnectionSession.class,
RETURNS_DEEP_STUBS);
when(result.getCurrentDatabaseName()).thenReturn("foo_db");
diff --git
a/proxy/frontend/dialect/postgresql/src/test/java/org/apache/shardingsphere/proxy/frontend/postgresql/command/query/extended/PostgreSQLBatchedStatementsExecutorTest.java
b/proxy/frontend/dialect/postgresql/src/test/java/org/apache/shardingsphere/proxy/frontend/postgresql/command/query/extended/PostgreSQLBatchedStatementsExecutorTest.java
index bf8ebb898b8..480754a1f36 100644
---
a/proxy/frontend/dialect/postgresql/src/test/java/org/apache/shardingsphere/proxy/frontend/postgresql/command/query/extended/PostgreSQLBatchedStatementsExecutorTest.java
+++
b/proxy/frontend/dialect/postgresql/src/test/java/org/apache/shardingsphere/proxy/frontend/postgresql/command/query/extended/PostgreSQLBatchedStatementsExecutorTest.java
@@ -25,6 +25,7 @@ import
org.apache.shardingsphere.infra.binder.context.statement.type.dml.InsertS
import
org.apache.shardingsphere.infra.binder.context.statement.type.dml.UpdateStatementContext;
import org.apache.shardingsphere.infra.config.props.ConfigurationProperties;
import org.apache.shardingsphere.infra.config.props.ConfigurationPropertyKey;
+import org.apache.shardingsphere.infra.executor.kernel.ExecutorEngine;
import org.apache.shardingsphere.infra.executor.sql.context.ExecutionContext;
import org.apache.shardingsphere.infra.executor.sql.context.ExecutionUnit;
import
org.apache.shardingsphere.infra.executor.sql.execute.engine.ConnectionMode;
@@ -41,6 +42,7 @@ import
org.apache.shardingsphere.infra.spi.type.typed.TypedSPILoader;
import org.apache.shardingsphere.mode.manager.ContextManager;
import
org.apache.shardingsphere.proxy.backend.connector.ProxyDatabaseConnectionManager;
import
org.apache.shardingsphere.proxy.backend.connector.jdbc.statement.JDBCBackendStatement;
+import org.apache.shardingsphere.proxy.backend.context.BackendExecutorContext;
import org.apache.shardingsphere.proxy.backend.context.ProxyContext;
import org.apache.shardingsphere.proxy.backend.session.ConnectionSession;
import
org.apache.shardingsphere.sql.parser.statement.core.segment.dml.assignment.SetAssignmentSegment;
@@ -73,7 +75,9 @@ import java.util.Properties;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.not;
import static org.junit.jupiter.api.Assertions.assertNull;
+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.anyInt;
@@ -115,7 +119,7 @@ class PostgreSQLBatchedStatementsExecutorTest {
new HintValueContext(),
Arrays.asList(PostgreSQLBinaryColumnType.INT4,
PostgreSQLBinaryColumnType.VARCHAR), Arrays.asList(0, 1));
List<List<Object>> parameterSets = Arrays.asList(Arrays.asList(1, new
PostgreSQLTypeUnspecifiedSQLParameter("foo")),
Arrays.asList(2, new
PostgreSQLTypeUnspecifiedSQLParameter("bar")), Arrays.asList(3, new
PostgreSQLTypeUnspecifiedSQLParameter("baz")));
-
when(ProxyContext.getInstance().getContextManager()).thenReturn(contextManager);
+ initBackendExecutorContext(contextManager);
PostgreSQLBatchedStatementsExecutor actual = new
PostgreSQLBatchedStatementsExecutor(connectionSession,
postgresqlPreparedStatement, parameterSets);
prepareExecutionUnitParameters(actual, parameterSets);
int actualUpdated = actual.executeBatch();
@@ -128,6 +132,32 @@ class PostgreSQLBatchedStatementsExecutorTest {
}
}
+ @Test
+ void assertExecuteBatchAfterRepeatedProxyLifecycle() throws SQLException {
+ Connection connection = mock(Connection.class, RETURNS_DEEP_STUBS);
+
when(connection.getMetaData().getURL()).thenReturn("jdbc:postgresql://127.0.0.1/db");
+ when(databaseConnectionManager.getConnections(any(),
nullable(String.class), anyInt(), anyInt(),
any(ConnectionMode.class))).thenReturn(Collections.singletonList(connection));
+ PreparedStatement preparedStatement = mock(PreparedStatement.class);
+ when(preparedStatement.getConnection()).thenReturn(connection);
+ when(preparedStatement.executeBatch()).thenReturn(new int[]{1, 1, 1});
+ when(backendStatement.createStorageResource(any(ExecutionUnit.class),
eq(connection), anyInt(), any(ConnectionMode.class),
any(StatementOption.class), nullable(DatabaseType.class)))
+ .thenReturn(preparedStatement);
+ ContextManager contextManager = mockContextManager(databaseType);
+ initBackendExecutorContext(contextManager);
+ final ExecutorEngine previousExecutorEngine =
BackendExecutorContext.getInstance().getExecutorEngine();
+ BackendExecutorContext.getInstance().shutdown();
+ assertThrows(IllegalStateException.class, () ->
BackendExecutorContext.getInstance().getExecutorEngine());
+ BackendExecutorContext.getInstance().init();
+ assertThat(BackendExecutorContext.getInstance().getExecutorEngine(),
is(not(previousExecutorEngine)));
+ PostgreSQLServerPreparedStatement postgresqlPreparedStatement = new
PostgreSQLServerPreparedStatement("INSERT INTO t (id, col) VALUES (?, ?)",
mockInsertStatementContext(),
+ new HintValueContext(),
Arrays.asList(PostgreSQLBinaryColumnType.INT4,
PostgreSQLBinaryColumnType.VARCHAR), Arrays.asList(0, 1));
+ List<List<Object>> parameterSets = Arrays.asList(Arrays.asList(1, new
PostgreSQLTypeUnspecifiedSQLParameter("foo")),
+ Arrays.asList(2, new
PostgreSQLTypeUnspecifiedSQLParameter("bar")), Arrays.asList(3, new
PostgreSQLTypeUnspecifiedSQLParameter("baz")));
+ PostgreSQLBatchedStatementsExecutor actual = new
PostgreSQLBatchedStatementsExecutor(mockConnectionSession(),
postgresqlPreparedStatement, parameterSets);
+ prepareExecutionUnitParameters(actual, parameterSets);
+ assertThat(actual.executeBatch(), is(3));
+ }
+
@Test
void assertExecuteBatchWhenExecuteBatchThrowsSQLException() throws
SQLException {
Connection connection = mock(Connection.class, RETURNS_DEEP_STUBS);
@@ -143,7 +173,7 @@ class PostgreSQLBatchedStatementsExecutorTest {
PostgreSQLServerPreparedStatement postgresqlPreparedStatement = new
PostgreSQLServerPreparedStatement("UPDATE t SET col = ? WHERE id = ?",
mockUpdateStatementContext(),
new HintValueContext(),
Arrays.asList(PostgreSQLBinaryColumnType.INT4,
PostgreSQLBinaryColumnType.VARCHAR), Arrays.asList(0, 1));
List<List<Object>> parameterSets =
Collections.singletonList(Arrays.asList(10, "foo"));
-
when(ProxyContext.getInstance().getContextManager()).thenReturn(contextManager);
+ initBackendExecutorContext(contextManager);
PostgreSQLBatchedStatementsExecutor actual = new
PostgreSQLBatchedStatementsExecutor(connectionSession,
postgresqlPreparedStatement, parameterSets);
prepareExecutionUnitParameters(actual, parameterSets);
try {
@@ -165,7 +195,7 @@ class PostgreSQLBatchedStatementsExecutorTest {
@Test
void assertCreateExecutorWithoutParameterSets() throws
ReflectiveOperationException {
ContextManager contextManager = mockContextManager(databaseType);
-
when(ProxyContext.getInstance().getContextManager()).thenReturn(contextManager);
+ initBackendExecutorContext(contextManager);
ConnectionSession connectionSession = mockConnectionSession();
PostgreSQLServerPreparedStatement postgresqlPreparedStatement = new
PostgreSQLServerPreparedStatement("INSERT INTO t (id, col) VALUES (?, ?)",
mockInsertStatementContext(),
new HintValueContext(),
Arrays.asList(PostgreSQLBinaryColumnType.INT4,
PostgreSQLBinaryColumnType.VARCHAR), Arrays.asList(0, 1));
@@ -182,7 +212,7 @@ class PostgreSQLBatchedStatementsExecutorTest {
@Test
void assertPrepareForRestOfParametersWithoutParameterAware() throws
ReflectiveOperationException {
ContextManager contextManager = mockContextManager(databaseType);
-
when(ProxyContext.getInstance().getContextManager()).thenReturn(contextManager);
+ initBackendExecutorContext(contextManager);
ConnectionSession connectionSession = mockConnectionSession();
PostgreSQLServerPreparedStatement postgresqlPreparedStatement = new
PostgreSQLServerPreparedStatement("UPDATE t SET col = ? WHERE id = ?",
mockUpdateStatementContext(),
new HintValueContext(),
Arrays.asList(PostgreSQLBinaryColumnType.INT4,
PostgreSQLBinaryColumnType.VARCHAR), Arrays.asList(0, 1));
@@ -194,6 +224,11 @@ class PostgreSQLBatchedStatementsExecutorTest {
assertThat(actualParamGroups, is(2));
}
+ private void initBackendExecutorContext(final ContextManager
contextManager) {
+
when(ProxyContext.getInstance().getContextManager()).thenReturn(contextManager);
+ BackendExecutorContext.getInstance().init();
+ }
+
private InsertStatementContext mockInsertStatementContext() {
InsertStatement insertStatement =
InsertStatement.builder().databaseType(databaseType).table(new
SimpleTableSegment(new TableNameSegment(0, 0, new
IdentifierValue("t")))).build();
InsertStatementContext result = mock(InsertStatementContext.class);