From 6f9cd40f5965443ecc5c364e1b3663a2ec418df6 Mon Sep 17 00:00:00 2001 From: "laywin@yeah.net" Date: Tue, 14 Nov 2023 15:04:39 +0800 Subject: [PATCH 1/2] undo_log table check optimize --- .../java/io/seata/core/constants/DBType.java | 17 +++++++++++ .../main/java/io/seata/rm/RMHandlerAT.java | 23 -------------- .../seata/rm/datasource/DataSourceProxy.java | 30 +++++++++++++++++++ .../java/io/seata/rm/RMHandlerATTest.java | 2 -- 4 files changed, 47 insertions(+), 25 deletions(-) diff --git a/core/src/main/java/io/seata/core/constants/DBType.java b/core/src/main/java/io/seata/core/constants/DBType.java index 49063bb802e..f1dc3ea9e3e 100644 --- a/core/src/main/java/io/seata/core/constants/DBType.java +++ b/core/src/main/java/io/seata/core/constants/DBType.java @@ -17,6 +17,8 @@ import io.seata.common.util.StringUtils; +import java.util.Optional; + /** * database type * @@ -209,4 +211,19 @@ public static DBType valueof(String dbType) { throw new IllegalArgumentException("unknown dbtype:" + dbType); } + + /** + * optional of db type. + * + * @param dbType the db type + * @return optional of the db type + */ + public static Optional optionalof(String dbType) { + for (DBType dt : values()) { + if (StringUtils.equalsIgnoreCase(dt.name(), dbType)) { + return Optional.of(dt); + } + } + return Optional.empty(); + } } diff --git a/rm-datasource/src/main/java/io/seata/rm/RMHandlerAT.java b/rm-datasource/src/main/java/io/seata/rm/RMHandlerAT.java index 333a121a295..cc9d1971890 100644 --- a/rm-datasource/src/main/java/io/seata/rm/RMHandlerAT.java +++ b/rm-datasource/src/main/java/io/seata/rm/RMHandlerAT.java @@ -19,8 +19,6 @@ import java.sql.SQLException; import java.text.ParseException; import java.util.Date; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; import io.seata.common.util.DateUtil; import io.seata.core.model.BranchType; @@ -44,8 +42,6 @@ public class RMHandlerAT extends AbstractRMHandler { private static final int LIMIT_ROWS = 3000; - private final Map undoLogTableExistRecord = new ConcurrentHashMap<>(); - @Override public void handle(UndoLogDeleteRequest request) { String resourceId = request.getResourceId(); @@ -56,12 +52,6 @@ public void handle(UndoLogDeleteRequest request) { return; } - boolean hasUndoLogTable = undoLogTableExistRecord.computeIfAbsent(resourceId, id -> checkUndoLogTableExist(dataSourceProxy)); - if (!hasUndoLogTable) { - LOGGER.debug("resource({}) has no undo_log table, UndoLogDeleteRequest will be ignored", resourceId); - return; - } - Date division = getLogCreated(request.getSaveDays()); UndoLogManager manager = getUndoLogManager(dataSourceProxy); @@ -80,19 +70,6 @@ public void handle(UndoLogDeleteRequest request) { } } - boolean checkUndoLogTableExist(DataSourceProxy dataSourceProxy) { - UndoLogManager manager = getUndoLogManager(dataSourceProxy); - try (Connection connection = getConnection(dataSourceProxy)) { - if (connection == null) { - return false; - } - return manager.hasUndoLogTable(connection); - } catch (Exception e) { - // should never happen, hasUndoLogTable method had catch all Exception - return false; - } - } - Connection getConnection(DataSourceProxy dataSourceProxy) { try { return dataSourceProxy.getPlainConnection(); diff --git a/rm-datasource/src/main/java/io/seata/rm/datasource/DataSourceProxy.java b/rm-datasource/src/main/java/io/seata/rm/datasource/DataSourceProxy.java index 48317a83516..1cf31acfe35 100644 --- a/rm-datasource/src/main/java/io/seata/rm/datasource/DataSourceProxy.java +++ b/rm-datasource/src/main/java/io/seata/rm/datasource/DataSourceProxy.java @@ -23,17 +23,24 @@ import javax.sql.DataSource; +import io.seata.common.ConfigurationKeys; import io.seata.common.Constants; +import io.seata.config.ConfigurationFactory; +import io.seata.core.constants.DBType; import io.seata.core.context.RootContext; import io.seata.core.model.BranchType; import io.seata.core.model.Resource; import io.seata.rm.DefaultResourceManager; import io.seata.rm.datasource.sql.struct.TableMetaCacheFactory; +import io.seata.rm.datasource.undo.UndoLogManager; +import io.seata.rm.datasource.undo.UndoLogManagerFactory; import io.seata.rm.datasource.util.JdbcUtils; import io.seata.sqlparser.util.JdbcConstants; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import static io.seata.common.DefaultValues.DEFAULT_TRANSACTION_UNDO_LOG_TABLE; + /** * The type Data source proxy. * @@ -92,6 +99,9 @@ private void init(DataSource dataSource, String resourceGroupId) { getMySQLAdaptiveType(connection); } version = selectDbVersion(connection); + + checkUndoLogTableExist(connection); + } catch (SQLException e) { throw new IllegalStateException("can not init dataSource", e); } @@ -120,6 +130,26 @@ private void getMySQLAdaptiveType(Connection connection) { } } + /** + * check existence of undolog table + * + * if the table not exist fast fail, or else keep silence + * + * @param conn db connection + */ + private void checkUndoLogTableExist(Connection conn) { + if (DBType.optionalof(dbType).isPresent()) { + UndoLogManager undoLogManager = UndoLogManagerFactory.getUndoLogManager(dbType); + boolean undoLogTableExist = undoLogManager.hasUndoLogTable(conn); + if (!undoLogTableExist) { + String undoLogTableName = ConfigurationFactory.getInstance() + .getConfig(ConfigurationKeys.TRANSACTION_UNDO_LOG_TABLE, DEFAULT_TRANSACTION_UNDO_LOG_TABLE); + String errMsg = String.format("in AT mode, %s table not exist", undoLogTableName); + throw new IllegalStateException(errMsg); + } + } + } + /** * publish tableMeta refresh event */ diff --git a/rm-datasource/src/test/java/io/seata/rm/RMHandlerATTest.java b/rm-datasource/src/test/java/io/seata/rm/RMHandlerATTest.java index 3ae96f51d0d..35fb5b3ba5c 100644 --- a/rm-datasource/src/test/java/io/seata/rm/RMHandlerATTest.java +++ b/rm-datasource/src/test/java/io/seata/rm/RMHandlerATTest.java @@ -48,7 +48,6 @@ void hasUndoLogTableTest() { for (int i = 0; i < testTimes; i++) { handler.handle(request); } - verify(handler, times(1)).checkUndoLogTableExist(any()); verify(handler, times(testTimes)).deleteUndoLog(any(), any(), any()); } @@ -60,7 +59,6 @@ void noUndoLogTableTest() { for (int i = 0; i < testTimes; i++) { handler.handle(request); } - verify(handler, times(1)).checkUndoLogTableExist(any()); verify(handler, never()).deleteUndoLog(any(), any(), any()); } From 92689496419218db60e57ee1bafc802385bb164d Mon Sep 17 00:00:00 2001 From: "laywin@yeah.net" Date: Tue, 14 Nov 2023 15:30:06 +0800 Subject: [PATCH 2/2] add modify record & fix unit test --- changes/en-us/2.0.0.md | 2 +- changes/zh-cn/2.0.0.md | 1 + .../src/test/java/io/seata/rm/RMHandlerATTest.java | 11 ----------- 3 files changed, 2 insertions(+), 12 deletions(-) diff --git a/changes/en-us/2.0.0.md b/changes/en-us/2.0.0.md index 49ee6f02f5d..d09eba093ec 100644 --- a/changes/en-us/2.0.0.md +++ b/changes/en-us/2.0.0.md @@ -151,7 +151,7 @@ The version is updated as follows: - [[#5951](https://github.com/seata/seata/pull/5951)] remove un support config in jdk17 - [[#5959](https://github.com/seata/seata/pull/5959)] modify code style and remove unused import - [[#6002](https://github.com/seata/seata/pull/6002)] remove fst serialization - +- [[#6030](https://github.com/seata/seata/pull/6030)] add a check for the existence of the undolog table ### security: - [[#5642](https://github.com/seata/seata/pull/5642)] add Hessian Serializer WhiteDenyList diff --git a/changes/zh-cn/2.0.0.md b/changes/zh-cn/2.0.0.md index 73012f63a0d..2d2fff0dd76 100644 --- a/changes/zh-cn/2.0.0.md +++ b/changes/zh-cn/2.0.0.md @@ -152,6 +152,7 @@ Seata 是一款开源的分布式事务解决方案,提供高性能和简单 - [[#5951](https://github.com/seata/seata/pull/5951)] 删除在 jdk17 中不支持的配置项 - [[#5959](https://github.com/seata/seata/pull/5959)] 修正代码风格问题及去除无用的类引用 - [[#6002](https://github.com/seata/seata/pull/6002)] 移除fst序列化模块 +- [[#6030](https://github.com/seata/seata/pull/6030)] 添加undo_log表的存在性校验 ### security: diff --git a/rm-datasource/src/test/java/io/seata/rm/RMHandlerATTest.java b/rm-datasource/src/test/java/io/seata/rm/RMHandlerATTest.java index 35fb5b3ba5c..f5a80f2dfea 100644 --- a/rm-datasource/src/test/java/io/seata/rm/RMHandlerATTest.java +++ b/rm-datasource/src/test/java/io/seata/rm/RMHandlerATTest.java @@ -51,17 +51,6 @@ void hasUndoLogTableTest() { verify(handler, times(testTimes)).deleteUndoLog(any(), any(), any()); } - @Test - void noUndoLogTableTest() { - RMHandlerAT handler = buildHandler(false); - UndoLogDeleteRequest request = buildRequest(); - int testTimes = 5; - for (int i = 0; i < testTimes; i++) { - handler.handle(request); - } - verify(handler, never()).deleteUndoLog(any(), any(), any()); - } - private RMHandlerAT buildHandler(boolean hasUndoLogTable) { RMHandlerAT handler = spy(new RMHandlerAT()); DataSourceManager dataSourceManager = mock(DataSourceManager.class);