From b44c6269077b45d69e4d1ec38a6f04cce59a5e03 Mon Sep 17 00:00:00 2001 From: LegGasai Date: Wed, 4 Dec 2024 09:23:42 +0800 Subject: [PATCH] bugfix: fix tablemeta refresh after closed (#7044) --- changes/en-us/2.x.md | 1 + changes/zh-cn/2.x.md | 1 + .../sql/struct/TableMetaCacheFactory.java | 37 ++++++++++++++++++- 3 files changed, 37 insertions(+), 2 deletions(-) diff --git a/changes/en-us/2.x.md b/changes/en-us/2.x.md index e72c9c481a6..789242cb85d 100644 --- a/changes/en-us/2.x.md +++ b/changes/en-us/2.x.md @@ -30,6 +30,7 @@ Add changes here for all PR submitted to the 2.x branch. - [[#7010](https://github.com/apache/incubator-seata/pull/7010)] fix error while the "context" is key word in DM8 when delete undolog - [[#7022](https://github.com/apache/incubator-seata/pull/7022)] fix `store.mode` property in `application.raft.example.yml` - [[#7025](https://github.com/apache/incubator-seata/pull/7025)] fix vGroupMappingManager is NOT init +- [[#7044](https://github.com/apache/incubator-seata/pull/7044)] fix tableMeta refresh after closed - ### optimize: - [[#6826](https://github.com/apache/incubator-seata/pull/6826)] remove the branch registration operation of the XA read-only transaction diff --git a/changes/zh-cn/2.x.md b/changes/zh-cn/2.x.md index 25cb1cd7fe1..abaa8d4fd93 100644 --- a/changes/zh-cn/2.x.md +++ b/changes/zh-cn/2.x.md @@ -30,6 +30,7 @@ - [[#7010](https://github.com/apache/incubator-seata/pull/7010)] 修复使用达梦数据库时删除undolog发生SQL语法错误 - [[#7022](https://github.com/apache/incubator-seata/pull/7022)] 修复 `application.raft.example.yml`的 `store.mode`属性 - [[#7025](https://github.com/apache/incubator-seata/pull/7025)] 修复vGroupMappingManager未初始化的问题 +- [[#7044](https://github.com/apache/incubator-seata/pull/7044)] 修复TableMeta在数据源关闭后刷新错误问题 ### optimize: - [[#6826](https://github.com/apache/incubator-seata/pull/6826)] 移除只读XA事务的分支注册操作 diff --git a/rm-datasource/src/main/java/org/apache/seata/rm/datasource/sql/struct/TableMetaCacheFactory.java b/rm-datasource/src/main/java/org/apache/seata/rm/datasource/sql/struct/TableMetaCacheFactory.java index b0048b32596..c956796ea12 100644 --- a/rm-datasource/src/main/java/org/apache/seata/rm/datasource/sql/struct/TableMetaCacheFactory.java +++ b/rm-datasource/src/main/java/org/apache/seata/rm/datasource/sql/struct/TableMetaCacheFactory.java @@ -17,6 +17,7 @@ package org.apache.seata.rm.datasource.sql.struct; import java.sql.Connection; +import java.sql.SQLException; import java.util.Map; import java.util.concurrent.BlockingQueue; import java.util.concurrent.ConcurrentHashMap; @@ -29,6 +30,7 @@ import org.apache.seata.common.loader.EnhancedServiceLoader; import org.apache.seata.common.thread.NamedThreadFactory; import org.apache.seata.common.util.CollectionUtils; +import org.apache.seata.common.util.StringUtils; import org.apache.seata.config.ConfigurationFactory; import org.apache.seata.rm.datasource.DataSourceProxy; import org.apache.seata.sqlparser.struct.TableMetaCache; @@ -99,6 +101,14 @@ public static void tableMetaRefreshEvent(String resourceId) { } } + /** + * Remove the TableMetaRefreshHolder from the map. + */ + private static void removeHolderFromMap(String resourceId) { + TABLE_META_REFRESH_HOLDER_MAP.remove(resourceId); + LOGGER.info("Removed TableMetaRefreshHolder for resourceId: {}", resourceId); + } + static class TableMetaRefreshHolder { private long lastRefreshFinishTime; private DataSourceProxy dataSource; @@ -133,6 +143,16 @@ static class TableMetaRefreshHolder { } lastRefreshFinishTime = System.nanoTime(); } + } catch (SQLException ex) { + if (isDataSourceClosedException(ex)) { + LOGGER.info("DataSource is closed, exiting refresh task for resourceId: {}", dataSource.getResourceId()); + removeHolderFromMap(dataSource.getResourceId()); + return; + } else { + // other error, avoid high CPU usage due to infinite loops caused by database exceptions + LOGGER.error("Table refresh SQL error: {}", ex.getMessage(), ex); + lastRefreshFinishTime = System.nanoTime(); + } } catch (Exception exx) { LOGGER.error("table refresh error:{}", exx.getMessage(), exx); // Avoid high CPU usage due to infinite loops caused by database exceptions @@ -142,7 +162,20 @@ static class TableMetaRefreshHolder { }); } - - + /** + * Helper method to determine if the exception is caused by the data source being closed. + * + * @param ex the SQLException to check + * @return true if the exception indicates the data source is closed; false otherwise + */ + private boolean isDataSourceClosedException(SQLException ex) { + String message = ex.getMessage().toLowerCase(); + String sqlState = ex.getSQLState(); + // Most jdbc drivers use '08006' as the datasource close code. + if ("08006".equals(sqlState)) { + return true; + } + return StringUtils.isNotBlank(message) && message.contains("datasource") && message.contains("close"); + } } }