From a4f046308072bf0c1d1fec831ad72c4e3bcc3484 Mon Sep 17 00:00:00 2001 From: ggbocoder <119659920+ggbocoder@users.noreply.github.com> Date: Sat, 24 Aug 2024 00:08:17 +0800 Subject: [PATCH 1/8] optimize: automatic deletion of namingserver vgroup through Caffeine map (#6770) --- changes/en-us/2.x.md | 2 +- changes/zh-cn/2.x.md | 1 + .../namingserver/NamingServerNode.java | 9 +++ dependencies/pom.xml | 6 ++ .../NamingserverRegistryServiceImpl.java | 12 +--- namingserver/pom.xml | 5 ++ .../namingserver/entity/bo/NamespaceBO.java | 8 +++ .../namingserver/manager/NamingManager.java | 58 ++++++++++++++----- .../namingserver/NamingControllerTest.java | 37 ------------ .../java/org/apache/seata/server/Server.java | 27 ++++++--- .../db/store/VGroupMappingDataBaseDAO.java | 3 +- 11 files changed, 94 insertions(+), 74 deletions(-) diff --git a/changes/en-us/2.x.md b/changes/en-us/2.x.md index 899fc783568..0baa90725d4 100644 --- a/changes/en-us/2.x.md +++ b/changes/en-us/2.x.md @@ -61,7 +61,7 @@ Add changes here for all PR submitted to the 2.x branch. - [[#6763](https://github.com/apache/incubator-seata/pull/6763)] optimize NacosConfiguration singleton reload - [[#6761](https://github.com/apache/incubator-seata/pull/6761)] optimize the namingserver code to improve readability - [[#6768](https://github.com/apache/incubator-seata/pull/6768)] report the tcc fence transaction isolation level - +- [[#6770](https://github.com/apache/incubator-seata/pull/6770)] Automatic deletion of namingserver vgroup through Caffeine map ### refactor: diff --git a/changes/zh-cn/2.x.md b/changes/zh-cn/2.x.md index 0371543adeb..f19513b8b45 100644 --- a/changes/zh-cn/2.x.md +++ b/changes/zh-cn/2.x.md @@ -61,6 +61,7 @@ - [[#6763](https://github.com/apache/incubator-seata/pull/6763)] 优化 NacosConfiguration 单例加载 - [[#6761](https://github.com/apache/incubator-seata/pull/6761)] 提升namingserver manager代码可读性 - [[#6768](https://github.com/apache/incubator-seata/pull/6768)] 上报tcc fence事务隔离级别 +- [[#6770](https://github.com/apache/incubator-seata/pull/6770)] 通过caffeine map支持namingserver事务分组的过期删除 ### refactor: diff --git a/common/src/main/java/org/apache/seata/common/metadata/namingserver/NamingServerNode.java b/common/src/main/java/org/apache/seata/common/metadata/namingserver/NamingServerNode.java index 5645ac0e3ed..459dd66b944 100644 --- a/common/src/main/java/org/apache/seata/common/metadata/namingserver/NamingServerNode.java +++ b/common/src/main/java/org/apache/seata/common/metadata/namingserver/NamingServerNode.java @@ -27,6 +27,15 @@ public class NamingServerNode extends Node { private double weight = 1.0; private boolean healthy = true; private long term; + private String unit; + + public String getUnit() { + return unit; + } + + public void setUnit(String unit) { + this.unit = unit; + } public double getWeight() { return weight; diff --git a/dependencies/pom.xml b/dependencies/pom.xml index e4887f5ca42..a94309cc3fc 100644 --- a/dependencies/pom.xml +++ b/dependencies/pom.xml @@ -111,6 +111,7 @@ 1.2.20 2.9.0 3.4.3 + 2.8.8 4.8 @@ -395,6 +396,11 @@ + + com.github.ben-manes.caffeine + caffeine + ${caffeine.version} + com.alibaba.spring spring-context-support diff --git a/discovery/seata-discovery-namingserver/src/main/java/org/apache/seata/discovery/registry/namingserver/NamingserverRegistryServiceImpl.java b/discovery/seata-discovery-namingserver/src/main/java/org/apache/seata/discovery/registry/namingserver/NamingserverRegistryServiceImpl.java index b8c988eb310..719336283d3 100644 --- a/discovery/seata-discovery-namingserver/src/main/java/org/apache/seata/discovery/registry/namingserver/NamingserverRegistryServiceImpl.java +++ b/discovery/seata-discovery-namingserver/src/main/java/org/apache/seata/discovery/registry/namingserver/NamingserverRegistryServiceImpl.java @@ -62,7 +62,6 @@ import org.slf4j.LoggerFactory; - public class NamingserverRegistryServiceImpl implements RegistryService { private static final Logger LOGGER = LoggerFactory.getLogger(NamingserverRegistryServiceImpl.class); @@ -163,15 +162,6 @@ public void register(InetSocketAddress address) throws Exception { heartBeatScheduledFuture.cancel(false); } - heartBeatScheduledFuture = this.executorService.scheduleAtFixedRate(() -> { - try { - instance.setTimestamp(System.currentTimeMillis()); - doRegister(instance, getNamingAddrs()); - } catch (Exception e) { - LOGGER.error("Naming server register Exception", e); - } - }, HEARTBEAT_PERIOD, HEARTBEAT_PERIOD, TimeUnit.MILLISECONDS); - } public void doRegister(Instance instance, List urlList) { @@ -232,7 +222,7 @@ public void unregister(InetSocketAddress address) { String unit = instance.getUnit(); String jsonBody = instance.toJsonString(); String params = "unit=" + unit; - params = params + "&cluster=" + instance.getClusterName(); + params = params + "&clusterName=" + instance.getClusterName(); params = params + "&namespace=" + instance.getNamespace(); url += params; Map header = new HashMap<>(); diff --git a/namingserver/pom.xml b/namingserver/pom.xml index 61e5b0bd8a6..4ed5764fa82 100644 --- a/namingserver/pom.xml +++ b/namingserver/pom.xml @@ -82,6 +82,11 @@ spring-boot-starter + + com.github.ben-manes.caffeine + caffeine + + org.springframework.boot spring-boot-starter-test diff --git a/namingserver/src/main/java/org/apache/seata/namingserver/entity/bo/NamespaceBO.java b/namingserver/src/main/java/org/apache/seata/namingserver/entity/bo/NamespaceBO.java index 907e0b25580..74749d8aac2 100644 --- a/namingserver/src/main/java/org/apache/seata/namingserver/entity/bo/NamespaceBO.java +++ b/namingserver/src/main/java/org/apache/seata/namingserver/entity/bo/NamespaceBO.java @@ -22,6 +22,7 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import org.apache.seata.common.metadata.Cluster; +import org.apache.seata.common.util.StringUtils; import org.apache.seata.namingserver.entity.pojo.ClusterData; public class NamespaceBO { @@ -54,4 +55,11 @@ public ClusterBO getCluster(String clusterName) { return clusterMap.computeIfAbsent(clusterName, k -> new ClusterBO()); } + public void removeOldCluster(String clusterName) { + clusterMap.keySet().forEach(currentClusterName -> { + if (!StringUtils.equals(currentClusterName, clusterName)) { + clusterMap.remove(currentClusterName); + } + }); + } } diff --git a/namingserver/src/main/java/org/apache/seata/namingserver/manager/NamingManager.java b/namingserver/src/main/java/org/apache/seata/namingserver/manager/NamingManager.java index 79a27bcfe8e..5de8ea9c5ae 100644 --- a/namingserver/src/main/java/org/apache/seata/namingserver/manager/NamingManager.java +++ b/namingserver/src/main/java/org/apache/seata/namingserver/manager/NamingManager.java @@ -33,6 +33,10 @@ import java.util.concurrent.atomic.AtomicReference; import javax.annotation.PostConstruct; +import com.github.benmanes.caffeine.cache.Caffeine; +import com.github.benmanes.caffeine.cache.LoadingCache; +import com.github.benmanes.caffeine.cache.RemovalCause; +import com.github.benmanes.caffeine.cache.RemovalListener; import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.entity.ContentType; import org.apache.http.protocol.HTTP; @@ -49,6 +53,8 @@ import org.apache.seata.namingserver.listener.ClusterChangeEvent; import org.apache.seata.namingserver.entity.pojo.ClusterData; import org.apache.seata.namingserver.entity.vo.monitor.ClusterVO; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.checkerframework.checker.nullness.qual.Nullable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -65,7 +71,7 @@ public class NamingManager { private static final Logger LOGGER = LoggerFactory.getLogger(NamingManager.class); private final ConcurrentMap instanceLiveTable; - private final ConcurrentMap> vGroupMap; + private volatile LoadingCache> vGroupMap; private final ConcurrentMap> namespaceClusterDataMap; @@ -83,12 +89,24 @@ public class NamingManager { public NamingManager() { this.instanceLiveTable = new ConcurrentHashMap<>(); - this.vGroupMap = new ConcurrentHashMap<>(); this.namespaceClusterDataMap = new ConcurrentHashMap<>(); } @PostConstruct public void init() { + this.vGroupMap = Caffeine.newBuilder() + .expireAfterAccess(heartbeatTimeThreshold, TimeUnit.MILLISECONDS) // expired time + .maximumSize(Integer.MAX_VALUE) + .removalListener(new RemovalListener() { + + @Override + public void onRemoval(@Nullable Object key, @Nullable Object value, @NonNull RemovalCause cause) { + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("vgroup map expired,vgroup:{},namespace:{}", key, value); + } + } + }) + .build(k -> new ConcurrentHashMap<>()); this.heartBeatCheckService.scheduleAtFixedRate(() -> { try { instanceHeartBeatCheck(); @@ -112,7 +130,7 @@ public List monitorCluster(String namespace) { LOGGER.warn("no cluster in namespace:" + namespace); } - vGroupMap.forEach((vGroup, namespaceMap) -> { + vGroupMap.asMap().forEach((vGroup, namespaceMap) -> { NamespaceBO namespaceBO = namespaceMap.get(namespace); if (namespaceBO != null) { namespaceBO.getClusterMap().forEach((clusterName, clusterBO) -> { @@ -161,6 +179,9 @@ public Result createGroup(String namespace, String vGroup, String cluste public Result removeGroup(String namespace, String clusterName,String vGroup, String unitName) { List clusterList = getClusterListByVgroup(vGroup, namespace); for (Cluster cluster : clusterList) { + if (!StringUtils.equals(clusterName, cluster.getClusterName())) { + continue; + } if (cluster.getUnitData() != null && cluster.getUnitData().size() > 0) { Unit unit = cluster.getUnitData().get(0); if (unit != null && unit.getNamingInstanceList() != null && unit.getNamingInstanceList().size() > 0) { @@ -194,19 +215,21 @@ public Result removeGroup(String namespace, String clusterName,String vG public void addGroup(String namespace, String clusterName, String unitName, String vGroup) { try { - ClusterBO clusterBO = vGroupMap.computeIfAbsent(vGroup, k -> new ConcurrentHashMap<>()) + ClusterBO clusterBO = vGroupMap.get(vGroup, k -> new ConcurrentHashMap<>()) .computeIfAbsent(namespace, k -> new NamespaceBO()).getCluster(clusterName); if (clusterBO != null && !clusterBO.getUnitNames().contains(unitName)) { clusterBO.addUnit(unitName); + NamespaceBO namespaceBO = vGroupMap.getIfPresent(vGroup).get(namespace); + namespaceBO.removeOldCluster(clusterName); applicationContext.publishEvent(new ClusterChangeEvent(this, vGroup, System.currentTimeMillis())); } } catch (Exception e) { - LOGGER.error("change vGroup mapping failed:{}", vGroup); + LOGGER.error("change vGroup mapping failed:{}", vGroup, e); } } public void notifyClusterChange(String namespace, String clusterName, String unitName, long term) { - vGroupMap.forEach((vGroup, namespaceMap) -> { + vGroupMap.asMap().forEach((vGroup, namespaceMap) -> { Optional.ofNullable(namespaceMap.get(namespace)) .flatMap(namespaceBO -> Optional.ofNullable(namespaceBO.getCluster(clusterName))) .ifPresent(clusterBO -> { @@ -239,7 +262,6 @@ public boolean registerInstance(NamingServerNode node, String namespace, String }); } }); - boolean hasChanged = clusterData.registerInstance(node, unitName); if (hasChanged) { notifyClusterChange(namespace, clusterName, unitName,node.getTerm()); @@ -263,8 +285,8 @@ public boolean unregisterInstance(String namespace, String clusterName, String u clusterData.removeInstance(node, unitName); Object vgroupMap = node.getMetadata().get(CONSTANT_GROUP); if (vgroupMap instanceof Map) { - ((Map)vgroupMap).forEach((group, realUnitName) -> vGroupMap.get(group) - .get(namespace).getCluster(clusterName).remove((String) realUnitName)); + ((Map) vgroupMap).forEach((group, realUnitName) -> vGroupMap.get(group, k -> new ConcurrentHashMap<>()) + .get(namespace).getCluster(clusterName).remove(realUnitName == null ? unitName : (String) realUnitName)); } notifyClusterChange(namespace, clusterName, unitName, node.getTerm()); instanceLiveTable.remove( @@ -272,7 +294,7 @@ public boolean unregisterInstance(String namespace, String clusterName, String u } } } catch (Exception e) { - LOGGER.error("Instance unregistered failed!"); + LOGGER.error("Instance unregistered failed!", e); return false; } return true; @@ -280,8 +302,8 @@ public boolean unregisterInstance(String namespace, String clusterName, String u public List getClusterListByVgroup(String vGroup, String namespace) { // find the cluster where the transaction group is located - ConcurrentMap vgroupNamespaceMap = - vGroupMap.get(vGroup); + HashMap> concurrentVgroupMap = new HashMap<>(vGroupMap.asMap()); + ConcurrentMap vgroupNamespaceMap = concurrentVgroupMap.get(vGroup); List clusterList = new ArrayList<>(); if (!CollectionUtils.isEmpty(vgroupNamespaceMap)) { NamespaceBO namespaceBO = vgroupNamespaceMap.get(namespace); @@ -325,9 +347,13 @@ public void instanceHeartBeatCheck() { if (vgoupMap instanceof Map) { ((Map)vgoupMap).forEach((group, unitName) -> { ClusterBO clusterBO = - vGroupMap.get(group).get(namespace).getCluster(clusterData.getClusterName()); + vGroupMap.get(group) + .computeIfAbsent(namespace, k -> new NamespaceBO()) + .getCluster(clusterData.getClusterName()); Set units = clusterBO.getUnitNames(); - units.remove((String)unitName); + if (units != null) { + units.remove(unitName == null ? instance.getUnit() : unitName); + } }); } @@ -352,10 +378,10 @@ public Result changeGroup(String namespace, String vGroup, String cluste if (StringUtils.equalsIgnoreCase(clusterName, currentCluster)) { continue; } - result.set(removeGroup(currentNamespace, clusterName, vGroup, unitName)); + result.set(removeGroup(currentNamespace, currentCluster, vGroup, unitName)); } else { if (!StringUtils.equalsIgnoreCase(unitName, currentUnitName)) { - result.set(removeGroup(currentNamespace, clusterName, vGroup, unitName)); + result.set(removeGroup(currentNamespace, currentCluster, vGroup, unitName)); } } } diff --git a/namingserver/src/test/java/org/apache/seata/namingserver/NamingControllerTest.java b/namingserver/src/test/java/org/apache/seata/namingserver/NamingControllerTest.java index 713a0117f4b..0a3ba29034b 100644 --- a/namingserver/src/test/java/org/apache/seata/namingserver/NamingControllerTest.java +++ b/namingserver/src/test/java/org/apache/seata/namingserver/NamingControllerTest.java @@ -263,41 +263,4 @@ void mockHeartbeat() throws InterruptedException { assertEquals(8091, node1.getTransaction().getPort()); } - @Test - void mockIntermediateState() { - String clusterName = "cluster1"; - String namespace = "public6"; - String vGroup = "vgroup1"; - String unitName = String.valueOf(UUID.randomUUID()); - NamingServerNode node = new NamingServerNode(); - node.setTransaction(new Node.Endpoint("127.0.0.1", 8091, "netty")); - node.setControl(new Node.Endpoint("127.0.0.1", 7091, "http")); - Map meatadata = node.getMetadata(); - Map vGroups = new HashMap<>(); - vGroups.put(vGroup,unitName); - meatadata.put(CONSTANT_GROUP, vGroups); - namingController.registerInstance(namespace, clusterName, unitName, node); - NamingServerNode node2 = new NamingServerNode(); - node2.setTransaction(new Node.Endpoint("127.0.0.1", 8092, "netty")); - node2.setControl(new Node.Endpoint("127.0.0.1", 7092, "http")); - Map meatadata2 = node2.getMetadata(); - Map vGroups2 = new HashMap<>(); - String unitName2 = UUID.randomUUID().toString(); - vGroups2.put(vGroup,unitName2); - meatadata2.put(CONSTANT_GROUP, vGroups2); - namingController.registerInstance(namespace, "clusterName2", unitName2, node2); - MetaResponse metaResponse = namingController.discovery(vGroup, namespace); - assertNotNull(metaResponse); - assertNotNull(metaResponse.getClusterList()); - assertEquals(2, metaResponse.getClusterList().size()); - Cluster cluster = metaResponse.getClusterList().get(1); - assertNotNull(cluster.getUnitData()); - assertEquals(1, cluster.getUnitData().size()); - Unit unit = cluster.getUnitData().get(0); - assertNotNull(unit.getNamingInstanceList()); - assertEquals(1, unit.getNamingInstanceList().size()); - Node unit2 = unit.getNamingInstanceList().get(0); - assertEquals(unit2.getTransaction(), node2.getTransaction()); - } - } \ No newline at end of file diff --git a/server/src/main/java/org/apache/seata/server/Server.java b/server/src/main/java/org/apache/seata/server/Server.java index f4923cdbdae..152ac0edf31 100644 --- a/server/src/main/java/org/apache/seata/server/Server.java +++ b/server/src/main/java/org/apache/seata/server/Server.java @@ -19,6 +19,8 @@ import java.util.Objects; import java.util.UUID; import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledThreadPoolExecutor; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; @@ -39,6 +41,8 @@ import org.apache.seata.server.session.SessionHolder; import org.apache.seata.server.store.StoreConfig; import org.apache.seata.server.store.VGroupMappingStoreManager; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import org.springframework.context.ApplicationListener; import org.springframework.core.env.ConfigurableEnvironment; @@ -63,6 +67,9 @@ * The type Server. */ public class Server { + private static final Logger LOGGER = LoggerFactory.getLogger(Server.class); + + protected static final ScheduledExecutorService EXECUTOR_SERVICE = new ScheduledThreadPoolExecutor(1, new NamedThreadFactory("scheduledExcuter", 1, true)); public static void metadataInit() { VGroupMappingStoreManager vGroupMappingStoreManager = SessionHolder.getRootVGroupMappingManager(); @@ -104,7 +111,13 @@ public static void metadataInit() { // load vgroup mapping relationship instance.addMetadata("vGroup", vGroupMappingStoreManager.loadVGroups()); } - vGroupMappingStoreManager.notifyMapping(); + EXECUTOR_SERVICE.scheduleAtFixedRate(() -> { + try { + vGroupMappingStoreManager.notifyMapping(); + } catch (Exception e) { + LOGGER.error("Naming server register Exception", e); + } + }, 0, 5000, TimeUnit.MILLISECONDS); } @@ -123,9 +136,9 @@ public static void start(String[] args) { MetricsManager.get().init(); ThreadPoolExecutor workingThreads = new ThreadPoolExecutor(NettyServerConfig.getMinServerPoolSize(), - NettyServerConfig.getMaxServerPoolSize(), NettyServerConfig.getKeepAliveTime(), TimeUnit.SECONDS, - new LinkedBlockingQueue<>(NettyServerConfig.getMaxTaskQueueSize()), - new NamedThreadFactory("ServerHandlerThread", NettyServerConfig.getMaxServerPoolSize()), new ThreadPoolExecutor.CallerRunsPolicy()); + NettyServerConfig.getMaxServerPoolSize(), NettyServerConfig.getKeepAliveTime(), TimeUnit.SECONDS, + new LinkedBlockingQueue<>(NettyServerConfig.getMaxTaskQueueSize()), + new NamedThreadFactory("ServerHandlerThread", NettyServerConfig.getMaxServerPoolSize()), new ThreadPoolExecutor.CallerRunsPolicy()); //127.0.0.1 and 0.0.0.0 are not valid here. if (NetUtil.isValidIp(parameterParser.getHost(), false)) { @@ -142,14 +155,14 @@ public static void start(String[] args) { XID.setPort(nettyRemotingServer.getListenPort()); UUIDGenerator.init(parameterParser.getServerNode()); ConfigurableListableBeanFactory beanFactory = - ((GenericWebApplicationContext) ObjectHolder.INSTANCE - .getObject(OBJECT_KEY_SPRING_APPLICATION_CONTEXT)).getBeanFactory(); + ((GenericWebApplicationContext) ObjectHolder.INSTANCE + .getObject(OBJECT_KEY_SPRING_APPLICATION_CONTEXT)).getBeanFactory(); DefaultCoordinator coordinator = DefaultCoordinator.getInstance(nettyRemotingServer); if (coordinator instanceof ApplicationListener) { beanFactory.registerSingleton(NettyRemotingServer.class.getName(), nettyRemotingServer); beanFactory.registerSingleton(DefaultCoordinator.class.getName(), coordinator); ((GenericWebApplicationContext) ObjectHolder.INSTANCE.getObject(OBJECT_KEY_SPRING_APPLICATION_CONTEXT)) - .addApplicationListener((ApplicationListener) coordinator); + .addApplicationListener((ApplicationListener) coordinator); } //log store mode : file, db, redis SessionHolder.init(); diff --git a/server/src/main/java/org/apache/seata/server/storage/db/store/VGroupMappingDataBaseDAO.java b/server/src/main/java/org/apache/seata/server/storage/db/store/VGroupMappingDataBaseDAO.java index 85c8faa13e6..ed2d68d6354 100644 --- a/server/src/main/java/org/apache/seata/server/storage/db/store/VGroupMappingDataBaseDAO.java +++ b/server/src/main/java/org/apache/seata/server/storage/db/store/VGroupMappingDataBaseDAO.java @@ -54,7 +54,6 @@ public VGroupMappingDataBaseDAO(DataSource vGroupMappingDataSource) { } public boolean insertMappingDO(MappingDO mappingDO) { - clearMappingDOByVGroup(mappingDO.getVGroup()); String sql = "INSERT INTO " + vMapping + " (vgroup,namespace, cluster) VALUES (?, ?, ?)"; Connection conn = null; PreparedStatement ps = null; @@ -105,7 +104,7 @@ public boolean deleteMappingDOByVGroup(String vGroup) { ps.setString(2, instance.getClusterName()); return ps.executeUpdate() > 0; } catch (SQLException e) { - throw new SeataRuntimeException(ErrorCode.ERROR_SQL,e); + throw new SeataRuntimeException(ErrorCode.ERROR_SQL, e); } finally { IOUtil.close(ps, conn); } From 64035c5feb7cf0e7f0356fb2ca5a7e25215851ca Mon Sep 17 00:00:00 2001 From: will <349071347@qq.com> Date: Sat, 24 Aug 2024 01:47:17 +0800 Subject: [PATCH 2/8] test: fix the wrong code coverage from codecov icon in default branch (#6773) --- README.md | 2 +- changes/en-us/2.x.md | 1 + changes/zh-cn/2.x.md | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index ecff43685d1..645a1587765 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ # Seata: Simple Extensible Autonomous Transaction Architecture [![Build Status](https://github.com/apache/incubator-seata/workflows/build/badge.svg?branch=develop)](https://github.com/apache/incubator-seata/actions) -[![codecov](https://codecov.io/gh/apache/incubator-seata/branch/develop/graph/badge.svg)](https://codecov.io/gh/apache/incubator-seata) +[![codecov](https://codecov.io/gh/apache/incubator-seata/graph/badge.svg?token=tbmHt2ZfxO)](https://codecov.io/gh/apache/incubator-seata) [![license](https://img.shields.io/github/license/apache/incubator-seata.svg)](https://www.apache.org/licenses/LICENSE-2.0.html) [![maven](https://img.shields.io/maven-central/v/io.apache/incubator-seata-parent?versionSuffix=2.0.0)](https://search.maven.org/search?q=io.seata) diff --git a/changes/en-us/2.x.md b/changes/en-us/2.x.md index 0baa90725d4..8e3433ad9fe 100644 --- a/changes/en-us/2.x.md +++ b/changes/en-us/2.x.md @@ -74,6 +74,7 @@ Add changes here for all PR submitted to the 2.x branch. - [[#6647](https://github.com/apache/incubator-seata/pull/6647)] improve the test case coverage of saga module to 70% - [[#6695](https://github.com/apache/incubator-seata/pull/6695)] old version(< 0.7.1) client test case for multi-version protocol - [[#6750](https://github.com/apache/incubator-seata/pull/6750)] increase spring autoconfigure module unit test converage +- [[#6773](https://github.com/apache/incubator-seata/pull/6773)] fix the wrong code coverage from codecov icon in default branch Thanks to these contributors for their code commits. Please report an unintended omission. diff --git a/changes/zh-cn/2.x.md b/changes/zh-cn/2.x.md index f19513b8b45..3594e35e1c0 100644 --- a/changes/zh-cn/2.x.md +++ b/changes/zh-cn/2.x.md @@ -76,7 +76,7 @@ - [[#6647](https://github.com/apache/incubator-seata/pull/6647)] 增加saga模块的测试用例覆盖率 - [[#6695](https://github.com/apache/incubator-seata/pull/6695)] 多版本协议的旧版本(< 0.7.1)客户端测试用例 - [[#6750](https://github.com/apache/incubator-seata/pull/6750)] 提升spring autoconfigure模块单测覆盖率 - +- [[#6773](https://github.com/apache/incubator-seata/pull/6773)] 修复codecov图标显示错误的代码覆盖率 From eba3e34fd6640e2706ff609eb0648191c41c4a00 Mon Sep 17 00:00:00 2001 From: ggbocoder <119659920+ggbocoder@users.noreply.github.com> Date: Sun, 25 Aug 2024 13:33:22 +0800 Subject: [PATCH 3/8] bugfix: fix the naming server node having a term of 0 (#6778) --- changes/en-us/2.x.md | 1 + changes/zh-cn/2.x.md | 1 + .../NamingserverRegistryServiceImpl.java | 2 +- .../controller/HealthController.java | 2 + .../controller/NamingController.java | 3 +- .../namingserver/manager/NamingManager.java | 37 +++++++++---------- script/server/db/mysql.sql | 2 +- .../java/org/apache/seata/server/Server.java | 2 + 8 files changed, 27 insertions(+), 23 deletions(-) diff --git a/changes/en-us/2.x.md b/changes/en-us/2.x.md index 8e3433ad9fe..b86184a08be 100644 --- a/changes/en-us/2.x.md +++ b/changes/en-us/2.x.md @@ -25,6 +25,7 @@ Add changes here for all PR submitted to the 2.x branch. - [[#6701](https://github.com/apache/incubator-seata/pull/6728)] fix support serialization for dm.jdbc.driver.DmdbTimestamp - [[#6757](https://github.com/apache/incubator-seata/pull/6757)] the bug where multiple nodes cannot be retrieved from the naming server - [[#6769](https://github.com/apache/incubator-seata/pull/6769)] fix tcc fence deadLock +- [[#6778](https://github.com/apache/incubator-seata/pull/6778)] fix namingserver node term ### optimize: diff --git a/changes/zh-cn/2.x.md b/changes/zh-cn/2.x.md index 3594e35e1c0..d2527d9578e 100644 --- a/changes/zh-cn/2.x.md +++ b/changes/zh-cn/2.x.md @@ -26,6 +26,7 @@ - [[#6701](https://github.com/apache/incubator-seata/pull/6728)] 修复达梦数据库的对dm.jdbc.driver.DmdbTimestamp的支持 - [[#6757](https://github.com/apache/incubator-seata/pull/6757)] 修复client通过namingserver只能获取到一个tc节点的bug - [[#6769](https://github.com/apache/incubator-seata/pull/6769)] 修复tcc fence死锁 +- [[#6778](https://github.com/apache/incubator-seata/pull/6778)] 修复namingserver的节点term为0问题 ### optimize: - [[#6499](https://github.com/apache/incubator-seata/pull/6499)] 拆分 committing 和 rollbacking 状态的任务线程池 diff --git a/discovery/seata-discovery-namingserver/src/main/java/org/apache/seata/discovery/registry/namingserver/NamingserverRegistryServiceImpl.java b/discovery/seata-discovery-namingserver/src/main/java/org/apache/seata/discovery/registry/namingserver/NamingserverRegistryServiceImpl.java index 719336283d3..ab78d48bbc9 100644 --- a/discovery/seata-discovery-namingserver/src/main/java/org/apache/seata/discovery/registry/namingserver/NamingserverRegistryServiceImpl.java +++ b/discovery/seata-discovery-namingserver/src/main/java/org/apache/seata/discovery/registry/namingserver/NamingserverRegistryServiceImpl.java @@ -196,7 +196,7 @@ public void doRegister(Instance instance, List urlList) { } public boolean doHealthCheck(String url) { - url = HTTP_PREFIX + url + "/health"; + url = HTTP_PREFIX + url + "/naming/v1/health"; Map header = new HashMap<>(); header.put(HTTP.CONTENT_TYPE, ContentType.APPLICATION_JSON.getMimeType()); try (CloseableHttpResponse response = HttpClientUtil.doGet(url, null, header, 3000)) { diff --git a/namingserver/src/main/java/org/apache/seata/namingserver/controller/HealthController.java b/namingserver/src/main/java/org/apache/seata/namingserver/controller/HealthController.java index a50ce1f08de..7fd77f8e631 100644 --- a/namingserver/src/main/java/org/apache/seata/namingserver/controller/HealthController.java +++ b/namingserver/src/main/java/org/apache/seata/namingserver/controller/HealthController.java @@ -18,9 +18,11 @@ import org.apache.seata.common.result.Result; import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController +@RequestMapping("/naming/v1") public class HealthController { @GetMapping("/health") diff --git a/namingserver/src/main/java/org/apache/seata/namingserver/controller/NamingController.java b/namingserver/src/main/java/org/apache/seata/namingserver/controller/NamingController.java index 3e1de73f965..a1630d3a464 100644 --- a/namingserver/src/main/java/org/apache/seata/namingserver/controller/NamingController.java +++ b/namingserver/src/main/java/org/apache/seata/namingserver/controller/NamingController.java @@ -132,11 +132,10 @@ public Result changeGroup(@RequestParam String namespace, public void watch(@RequestParam String clientTerm, @RequestParam String vGroup, @RequestParam String timeout, - @RequestParam String clientAddr, HttpServletRequest request) { AsyncContext context = request.startAsync(); context.setTimeout(0L); - Watcher watcher = new Watcher<>(vGroup, context, Integer.parseInt(timeout), Long.parseLong(clientTerm), clientAddr); + Watcher watcher = new Watcher<>(vGroup, context, Integer.parseInt(timeout), Long.parseLong(clientTerm), request.getRemoteAddr()); clusterWatcherManager.registryWatcher(watcher); } diff --git a/namingserver/src/main/java/org/apache/seata/namingserver/manager/NamingManager.java b/namingserver/src/main/java/org/apache/seata/namingserver/manager/NamingManager.java index 5de8ea9c5ae..09fa57d7519 100644 --- a/namingserver/src/main/java/org/apache/seata/namingserver/manager/NamingManager.java +++ b/namingserver/src/main/java/org/apache/seata/namingserver/manager/NamingManager.java @@ -228,16 +228,13 @@ public void addGroup(String namespace, String clusterName, String unitName, Stri } } - public void notifyClusterChange(String namespace, String clusterName, String unitName, long term) { - vGroupMap.asMap().forEach((vGroup, namespaceMap) -> { - Optional.ofNullable(namespaceMap.get(namespace)) - .flatMap(namespaceBO -> Optional.ofNullable(namespaceBO.getCluster(clusterName))) - .ifPresent(clusterBO -> { - Set units = clusterBO.getUnitNames(); - if (StringUtils.isBlank(unitName) || units.contains(unitName)) { - applicationContext.publishEvent(new ClusterChangeEvent(this, vGroup, term)); - } - }); + public void notifyClusterChange(String vGroup, String namespace, String clusterName, String unitName, long term) { + + Optional.ofNullable(vGroupMap.asMap().get(vGroup)).flatMap(map -> Optional.ofNullable(map.get(namespace)).flatMap(namespaceBO -> Optional.ofNullable(namespaceBO.getCluster(clusterName)))).ifPresent(clusterBO -> { + Set units = clusterBO.getUnitNames(); + if (StringUtils.isBlank(unitName) || units.contains(unitName)) { + applicationContext.publishEvent(new ClusterChangeEvent(this, vGroup, term)); + } }); } @@ -250,7 +247,7 @@ public boolean registerInstance(NamingServerNode node, String namespace, String // create cluster when there is no cluster in clusterDataHashMap ClusterData clusterData = clusterDataHashMap.computeIfAbsent(clusterName, key -> new ClusterData(clusterName, (String)node.getMetadata().get("cluster-type"))); - + boolean hasChanged = clusterData.registerInstance(node, unitName); // if extended metadata includes vgroup mapping relationship, add it in clusterData Optional.ofNullable(node.getMetadata().get(CONSTANT_GROUP)).ifPresent(mappingObj -> { if (mappingObj instanceof Map) { @@ -259,13 +256,12 @@ public boolean registerInstance(NamingServerNode node, String namespace, String // In non-raft mode, a unit is one-to-one with a node, and the unitName is stored on the node. // In raft mode, the unitName is equal to the raft-group, so the node's unitName cannot be used. addGroup(namespace, clusterName, StringUtils.isBlank(v) ? unitName : v, k); + if (hasChanged) { + notifyClusterChange(k,namespace, clusterName, unitName,node.getTerm()); + } }); } }); - boolean hasChanged = clusterData.registerInstance(node, unitName); - if (hasChanged) { - notifyClusterChange(namespace, clusterName, unitName,node.getTerm()); - } instanceLiveTable.put( new InetSocketAddress(node.getTransaction().getHost(), node.getTransaction().getPort()), System.currentTimeMillis()); @@ -285,10 +281,13 @@ public boolean unregisterInstance(String namespace, String clusterName, String u clusterData.removeInstance(node, unitName); Object vgroupMap = node.getMetadata().get(CONSTANT_GROUP); if (vgroupMap instanceof Map) { - ((Map) vgroupMap).forEach((group, realUnitName) -> vGroupMap.get(group, k -> new ConcurrentHashMap<>()) - .get(namespace).getCluster(clusterName).remove(realUnitName == null ? unitName : (String) realUnitName)); + ((Map) vgroupMap).forEach((group, realUnitName) -> { + vGroupMap.get(group, k -> new ConcurrentHashMap<>()) + .get(namespace).getCluster(clusterName).remove(realUnitName == null ? unitName : (String) realUnitName); + notifyClusterChange(group, namespace, clusterName, unitName, node.getTerm()); + }); } - notifyClusterChange(namespace, clusterName, unitName, node.getTerm()); + instanceLiveTable.remove( new InetSocketAddress(node.getTransaction().getHost(), node.getTransaction().getPort())); } @@ -353,6 +352,7 @@ public void instanceHeartBeatCheck() { Set units = clusterBO.getUnitNames(); if (units != null) { units.remove(unitName == null ? instance.getUnit() : unitName); + notifyClusterChange(group,namespace, clusterData.getClusterName(), unit.getUnitName(),-1); } }); } @@ -360,7 +360,6 @@ public void instanceHeartBeatCheck() { LOGGER.warn("{} instance has gone offline", instance.getTransaction().getHost() + ":" + instance.getTransaction().getPort()); } - notifyClusterChange(namespace, clusterData.getClusterName(), unit.getUnitName(),-1); } } } diff --git a/script/server/db/mysql.sql b/script/server/db/mysql.sql index fe0811dded2..552515a7519 100644 --- a/script/server/db/mysql.sql +++ b/script/server/db/mysql.sql @@ -95,6 +95,6 @@ CREATE TABLE IF NOT EXISTS `vgroup_table` `vGroup` VARCHAR(255), `namespace` VARCHAR(255), `cluster` VARCHAR(255), - primary key (`vGroup`) + UNIQUE KEY `idx_vgroup_namespace_cluster` (`vGroup`,`namespace`,`cluster`) ) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4; \ No newline at end of file diff --git a/server/src/main/java/org/apache/seata/server/Server.java b/server/src/main/java/org/apache/seata/server/Server.java index 152ac0edf31..8289ded6b8d 100644 --- a/server/src/main/java/org/apache/seata/server/Server.java +++ b/server/src/main/java/org/apache/seata/server/Server.java @@ -93,6 +93,8 @@ public static void metadataInit() { // load unit name instance.setUnit(String.valueOf(UUID.randomUUID())); + instance.setTerm(System.currentTimeMillis()); + // load node Endpoint instance.setControl(new Node.Endpoint(NetUtil.getLocalIp(), Integer.parseInt(Objects.requireNonNull(environment.getProperty("server.port"))), "http")); From 8288a5750acff48c4f7bb9e6a45225095994a823 Mon Sep 17 00:00:00 2001 From: smartscity Date: Sun, 25 Aug 2024 22:43:19 +0800 Subject: [PATCH 4/8] bugfix: Resolve MySQL Driver Loading Issue (#6760) (#6765) --- changes/en-us/2.x.md | 1 + changes/zh-cn/2.x.md | 2 + .../store/db/AbstractDataSourceProvider.java | 66 +------------------ .../db/AbstractDataSourceProviderTest.java | 9 +++ 4 files changed, 13 insertions(+), 65 deletions(-) diff --git a/changes/en-us/2.x.md b/changes/en-us/2.x.md index b86184a08be..c189f9cc0c3 100644 --- a/changes/en-us/2.x.md +++ b/changes/en-us/2.x.md @@ -26,6 +26,7 @@ Add changes here for all PR submitted to the 2.x branch. - [[#6757](https://github.com/apache/incubator-seata/pull/6757)] the bug where multiple nodes cannot be retrieved from the naming server - [[#6769](https://github.com/apache/incubator-seata/pull/6769)] fix tcc fence deadLock - [[#6778](https://github.com/apache/incubator-seata/pull/6778)] fix namingserver node term +- [[#6765](https://github.com/apache/incubator-seata/pull/6765)] fix MySQL driver loading by replacing custom classloader with system classloader for better compatibility and simplified process ### optimize: diff --git a/changes/zh-cn/2.x.md b/changes/zh-cn/2.x.md index d2527d9578e..1ccc432ae68 100644 --- a/changes/zh-cn/2.x.md +++ b/changes/zh-cn/2.x.md @@ -27,6 +27,8 @@ - [[#6757](https://github.com/apache/incubator-seata/pull/6757)] 修复client通过namingserver只能获取到一个tc节点的bug - [[#6769](https://github.com/apache/incubator-seata/pull/6769)] 修复tcc fence死锁 - [[#6778](https://github.com/apache/incubator-seata/pull/6778)] 修复namingserver的节点term为0问题 +- [[#6765](https://github.com/apache/incubator-seata/pull/6765)] 改进MySQL驱动加载机制,将自定义类加载器替换为系统类加载器,更兼容简化流程 + ### optimize: - [[#6499](https://github.com/apache/incubator-seata/pull/6499)] 拆分 committing 和 rollbacking 状态的任务线程池 diff --git a/core/src/main/java/org/apache/seata/core/store/db/AbstractDataSourceProvider.java b/core/src/main/java/org/apache/seata/core/store/db/AbstractDataSourceProvider.java index 2287fcd3b85..9cca970ea69 100644 --- a/core/src/main/java/org/apache/seata/core/store/db/AbstractDataSourceProvider.java +++ b/core/src/main/java/org/apache/seata/core/store/db/AbstractDataSourceProvider.java @@ -16,15 +16,6 @@ */ package org.apache.seata.core.store.db; -import java.io.File; -import java.net.MalformedURLException; -import java.net.URL; -import java.net.URLClassLoader; -import java.util.HashMap; -import java.util.Map; -import java.util.Objects; -import java.util.stream.Stream; - import javax.sql.DataSource; import org.apache.seata.common.exception.StoreException; @@ -56,20 +47,8 @@ public abstract class AbstractDataSourceProvider implements DataSourceProvider, */ protected static final Configuration CONFIG = ConfigurationFactory.getInstance(); - private final static String MYSQL_DRIVER_CLASS_NAME = "com.mysql.jdbc.Driver"; - - private final static String MYSQL8_DRIVER_CLASS_NAME = "com.mysql.cj.jdbc.Driver"; - - private final static String MYSQL_DRIVER_FILE_PREFIX = "mysql-connector-java-"; - - private final static Map MYSQL_DRIVER_LOADERS; - private static final long DEFAULT_DB_MAX_WAIT = 5000; - static { - MYSQL_DRIVER_LOADERS = createMysqlDriverClassLoaders(); - } - @Override public void init() { this.dataSource = generate(); @@ -145,50 +124,7 @@ protected Long getMaxWait() { } protected ClassLoader getDriverClassLoader() { - return MYSQL_DRIVER_LOADERS.getOrDefault(getDriverClassName(), ClassLoader.getSystemClassLoader()); - } - - private static Map createMysqlDriverClassLoaders() { - Map loaders = new HashMap<>(); - String cp = System.getProperty("java.class.path"); - if (cp == null || cp.isEmpty()) { - return loaders; - } - Stream.of(cp.split(File.pathSeparator)) - .map(File::new) - .filter(File::exists) - .map(file -> file.isFile() ? file.getParentFile() : file) - .filter(Objects::nonNull) - .filter(File::isDirectory) - .map(file -> new File(file, "jdbc")) - .filter(File::exists) - .filter(File::isDirectory) - .distinct() - .flatMap(file -> { - File[] files = file.listFiles((f, name) -> name.startsWith(MYSQL_DRIVER_FILE_PREFIX)); - if (files != null) { - return Stream.of(files); - } else { - return Stream.of(); - } - }) - .forEach(file -> { - if (loaders.containsKey(MYSQL8_DRIVER_CLASS_NAME) && loaders.containsKey(MYSQL_DRIVER_CLASS_NAME)) { - return; - } - try { - URL url = file.toURI().toURL(); - ClassLoader loader = new URLClassLoader(new URL[]{url}, ClassLoader.getSystemClassLoader()); - try { - loader.loadClass(MYSQL8_DRIVER_CLASS_NAME); - loaders.putIfAbsent(MYSQL8_DRIVER_CLASS_NAME, loader); - } catch (ClassNotFoundException e) { - loaders.putIfAbsent(MYSQL_DRIVER_CLASS_NAME, loader); - } - } catch (MalformedURLException ignore) { - } - }); - return loaders; + return ClassLoader.getSystemClassLoader(); } /** diff --git a/server/src/test/java/org/apache/seata/server/store/db/AbstractDataSourceProviderTest.java b/server/src/test/java/org/apache/seata/server/store/db/AbstractDataSourceProviderTest.java index 1b29b15c4e3..a0d8c9f8fe9 100644 --- a/server/src/test/java/org/apache/seata/server/store/db/AbstractDataSourceProviderTest.java +++ b/server/src/test/java/org/apache/seata/server/store/db/AbstractDataSourceProviderTest.java @@ -35,6 +35,8 @@ public class AbstractDataSourceProviderTest { private final String hikariDatasourceType = "hikari"; + private final String mysqlJdbcDriver = "com.mysql.jdbc.Driver"; + @Test public void testDbcpDataSourceProvider() { DataSource dataSource = EnhancedServiceLoader.load(DataSourceProvider.class, dbcpDatasourceType).provide(); @@ -52,4 +54,11 @@ public void testHikariDataSourceProvider() { DataSource dataSource = EnhancedServiceLoader.load(DataSourceProvider.class, hikariDatasourceType).provide(); Assertions.assertNotNull(dataSource); } + + @Test + public void testMySQLDataSourceProvider() throws ClassNotFoundException { + ClassLoader classLoader = ClassLoader.getSystemClassLoader(); + Class driverClass = Class.forName(mysqlJdbcDriver, true, classLoader); + Assertions.assertNotNull(driverClass); + } } From 8af2d8448b7958eef2c69f6c3ffd99ac7ca23dc5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E8=89=AF?= <841369634@qq.com> Date: Mon, 26 Aug 2024 11:49:38 +0800 Subject: [PATCH 5/8] optimize: optimize the reflection operation in class `SerializerServiceLoader` (#6780) --- changes/en-us/2.x.md | 1 + changes/zh-cn/2.x.md | 1 + .../apache/seata/common/util/ReflectionUtil.java | 15 +++++++++++++++ .../seata/common/util/ReflectionUtilTest.java | 6 ++++++ .../core/serializer/SerializerServiceLoader.java | 13 ++++++------- 5 files changed, 29 insertions(+), 7 deletions(-) diff --git a/changes/en-us/2.x.md b/changes/en-us/2.x.md index c189f9cc0c3..e9a57c4bf92 100644 --- a/changes/en-us/2.x.md +++ b/changes/en-us/2.x.md @@ -64,6 +64,7 @@ Add changes here for all PR submitted to the 2.x branch. - [[#6761](https://github.com/apache/incubator-seata/pull/6761)] optimize the namingserver code to improve readability - [[#6768](https://github.com/apache/incubator-seata/pull/6768)] report the tcc fence transaction isolation level - [[#6770](https://github.com/apache/incubator-seata/pull/6770)] Automatic deletion of namingserver vgroup through Caffeine map +- [[#6780](https://github.com/apache/incubator-seata/pull/6780)] optimize the reflection operation in class `SerializerServiceLoader` ### refactor: diff --git a/changes/zh-cn/2.x.md b/changes/zh-cn/2.x.md index 1ccc432ae68..d38a48d2d81 100644 --- a/changes/zh-cn/2.x.md +++ b/changes/zh-cn/2.x.md @@ -65,6 +65,7 @@ - [[#6761](https://github.com/apache/incubator-seata/pull/6761)] 提升namingserver manager代码可读性 - [[#6768](https://github.com/apache/incubator-seata/pull/6768)] 上报tcc fence事务隔离级别 - [[#6770](https://github.com/apache/incubator-seata/pull/6770)] 通过caffeine map支持namingserver事务分组的过期删除 +- [[#6780](https://github.com/apache/incubator-seata/pull/6780)] 优化类 `SerializerServiceLoader` 中的反射操作 ### refactor: diff --git a/common/src/main/java/org/apache/seata/common/util/ReflectionUtil.java b/common/src/main/java/org/apache/seata/common/util/ReflectionUtil.java index b9ba762bef6..5da00a4b611 100644 --- a/common/src/main/java/org/apache/seata/common/util/ReflectionUtil.java +++ b/common/src/main/java/org/apache/seata/common/util/ReflectionUtil.java @@ -89,6 +89,21 @@ public static Class getClassByName(String className) throws ClassNotFoundExce return Class.forName(className, true, Thread.currentThread().getContextClassLoader()); } + /** + * Is class present boolean. + * + * @param className the class name + * @return boolean true if the class is present + */ + public static boolean isClassPresent(String className) { + try { + Class.forName(className, false, Thread.currentThread().getContextClassLoader()); + return true; + } catch (ClassNotFoundException e) { + return false; + } + } + /** * Get the wrapped class * diff --git a/common/src/test/java/org/apache/seata/common/util/ReflectionUtilTest.java b/common/src/test/java/org/apache/seata/common/util/ReflectionUtilTest.java index 20f22c8be7a..7a1c390c14b 100644 --- a/common/src/test/java/org/apache/seata/common/util/ReflectionUtilTest.java +++ b/common/src/test/java/org/apache/seata/common/util/ReflectionUtilTest.java @@ -45,6 +45,12 @@ public void testGetClassByName() throws ClassNotFoundException { ReflectionUtil.getClassByName("java.lang.String")); } + @Test + public void testIsClassPresent() { + Assertions.assertTrue(ReflectionUtil.isClassPresent("java.lang.String")); + Assertions.assertFalse(ReflectionUtil.isClassPresent("java.lang.String2")); + } + @Test public void testGetWrappedClass() { Assertions.assertEquals(Byte.class, ReflectionUtil.getWrappedClass(byte.class)); diff --git a/core/src/main/java/org/apache/seata/core/serializer/SerializerServiceLoader.java b/core/src/main/java/org/apache/seata/core/serializer/SerializerServiceLoader.java index 0503fa8f731..63ce440edd1 100644 --- a/core/src/main/java/org/apache/seata/core/serializer/SerializerServiceLoader.java +++ b/core/src/main/java/org/apache/seata/core/serializer/SerializerServiceLoader.java @@ -56,6 +56,7 @@ private SerializerServiceLoader() { } private static final String PROTOBUF_SERIALIZER_CLASS_NAME = "org.apache.seata.serializer.protobuf.ProtobufSerializer"; + private static final boolean CONTAINS_PROTOBUF_DEPENDENCY = ReflectionUtil.isClassPresent(PROTOBUF_SERIALIZER_CLASS_NAME); /** * Load the service of {@link Serializer} @@ -65,15 +66,13 @@ private SerializerServiceLoader() { * @throws EnhancedServiceNotFoundException the enhanced service not found exception */ public static Serializer load(SerializerType type, byte version) throws EnhancedServiceNotFoundException { - if (type == SerializerType.PROTOBUF) { - try { - ReflectionUtil.getClassByName(PROTOBUF_SERIALIZER_CLASS_NAME); - } catch (ClassNotFoundException e) { - throw new EnhancedServiceNotFoundException("'ProtobufSerializer' not found. " + - "Please manually reference 'org.apache.seata:seata-serializer-protobuf' dependency ", e); - } + // The following code is only used to kindly prompt users to add missing dependencies. + if (type == SerializerType.PROTOBUF && !CONTAINS_PROTOBUF_DEPENDENCY) { + throw new EnhancedServiceNotFoundException("The class '" + PROTOBUF_SERIALIZER_CLASS_NAME + "' not found. " + + "Please manually reference 'org.apache.seata:seata-serializer-protobuf' dependency."); } + String key = serialzerKey(type, version); Serializer serializer = SERIALIZER_MAP.get(key); if (serializer == null) { From d7e780c39d453353ebde3b1c108c4dae5533a8ff Mon Sep 17 00:00:00 2001 From: funkye Date: Mon, 26 Aug 2024 21:11:13 +0800 Subject: [PATCH 6/8] bugfix: the issue where the TC occasionally fails to go offline from the NamingServer (#6781) --- changes/en-us/2.x.md | 1 + changes/zh-cn/2.x.md | 1 + .../namingserver/entity/pojo/ClusterData.java | 8 +- .../namingserver/manager/NamingManager.java | 99 +++++++++---------- script/client/conf/registry.conf | 7 +- script/client/spring/application.properties | 3 + script/client/spring/application.yml | 4 + .../SeataCoreEnvironmentPostProcessor.java | 3 + .../boot/autoconfigure/StarterConstants.java | 2 + .../RegistryNamingServerProperties.java | 66 +++++++++++++ .../java/org/apache/seata/server/Server.java | 50 +++++----- .../org/apache/seata/server/ServerRunner.java | 6 +- .../DataBaseVGroupMappingStoreManager.java | 2 +- .../db/store/VGroupMappingDataBaseDAO.java | 3 +- .../store/RedisVGroupMappingStoreManager.java | 9 +- .../store/VGroupMappingStoreManager.java | 7 +- .../main/resources/application.example.yml | 6 +- 17 files changed, 186 insertions(+), 91 deletions(-) create mode 100644 seata-spring-autoconfigure/seata-spring-autoconfigure-core/src/main/java/org/apache/seata/spring/boot/autoconfigure/properties/registry/RegistryNamingServerProperties.java diff --git a/changes/en-us/2.x.md b/changes/en-us/2.x.md index e9a57c4bf92..3de47dd8d0a 100644 --- a/changes/en-us/2.x.md +++ b/changes/en-us/2.x.md @@ -27,6 +27,7 @@ Add changes here for all PR submitted to the 2.x branch. - [[#6769](https://github.com/apache/incubator-seata/pull/6769)] fix tcc fence deadLock - [[#6778](https://github.com/apache/incubator-seata/pull/6778)] fix namingserver node term - [[#6765](https://github.com/apache/incubator-seata/pull/6765)] fix MySQL driver loading by replacing custom classloader with system classloader for better compatibility and simplified process +- [[#6781](https://github.com/apache/incubator-seata/pull/6781)] the issue where the TC occasionally fails to go offline from the NamingServer ### optimize: diff --git a/changes/zh-cn/2.x.md b/changes/zh-cn/2.x.md index d38a48d2d81..2b440e474b2 100644 --- a/changes/zh-cn/2.x.md +++ b/changes/zh-cn/2.x.md @@ -28,6 +28,7 @@ - [[#6769](https://github.com/apache/incubator-seata/pull/6769)] 修复tcc fence死锁 - [[#6778](https://github.com/apache/incubator-seata/pull/6778)] 修复namingserver的节点term为0问题 - [[#6765](https://github.com/apache/incubator-seata/pull/6765)] 改进MySQL驱动加载机制,将自定义类加载器替换为系统类加载器,更兼容简化流程 +- [[#6781](https://github.com/apache/incubator-seata/pull/6781)] 修复tc下线时,由于定时任务没有先关闭,导致下线后还会被注册上,需要靠namingserver的健康检查来下线的bug ### optimize: diff --git a/namingserver/src/main/java/org/apache/seata/namingserver/entity/pojo/ClusterData.java b/namingserver/src/main/java/org/apache/seata/namingserver/entity/pojo/ClusterData.java index 250f8509388..971b768e40c 100644 --- a/namingserver/src/main/java/org/apache/seata/namingserver/entity/pojo/ClusterData.java +++ b/namingserver/src/main/java/org/apache/seata/namingserver/entity/pojo/ClusterData.java @@ -42,20 +42,20 @@ public class ClusterData { private String clusterType; private final Map unitData; - private Lock lock = new ReentrantLock(); + private final Lock lock = new ReentrantLock(); public ClusterData() { - unitData = new ConcurrentHashMap<>(32); + this.unitData = new ConcurrentHashMap<>(); } public ClusterData(String clusterName) { - unitData = new ConcurrentHashMap<>(32); + this.unitData = new ConcurrentHashMap<>(); this.clusterName = clusterName; } public ClusterData(String clusterName, String clusterType) { - unitData = new ConcurrentHashMap<>(32); + unitData = new ConcurrentHashMap<>(); this.clusterName = clusterName; this.clusterType = clusterType; } diff --git a/namingserver/src/main/java/org/apache/seata/namingserver/manager/NamingManager.java b/namingserver/src/main/java/org/apache/seata/namingserver/manager/NamingManager.java index 09fa57d7519..bd89851b32e 100644 --- a/namingserver/src/main/java/org/apache/seata/namingserver/manager/NamingManager.java +++ b/namingserver/src/main/java/org/apache/seata/namingserver/manager/NamingManager.java @@ -19,6 +19,7 @@ import java.io.IOException; import java.net.InetSocketAddress; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.ArrayList; @@ -167,47 +168,38 @@ public Result createGroup(String namespace, String vGroup, String cluste return new Result<>(String.valueOf(closeableHttpResponse.getStatusLine().getStatusCode()), "add vGroup in new cluster failed"); } + LOGGER.info("namespace: {} add vGroup: {} in new cluster: {} successfully!", namespace, vGroup, clusterName); } catch (IOException e) { LOGGER.warn("add vGroup in new cluster failed"); return new Result<>("500", "add vGroup in new cluster failed"); } } - addGroup(namespace,clusterName,unitName,vGroup); return new Result<>("200", "add vGroup successfully!"); } - public Result removeGroup(String namespace, String clusterName,String vGroup, String unitName) { - List clusterList = getClusterListByVgroup(vGroup, namespace); - for (Cluster cluster : clusterList) { - if (!StringUtils.equals(clusterName, cluster.getClusterName())) { - continue; - } - if (cluster.getUnitData() != null && cluster.getUnitData().size() > 0) { - Unit unit = cluster.getUnitData().get(0); - if (unit != null && unit.getNamingInstanceList() != null && unit.getNamingInstanceList().size() > 0) { - Node node = unit.getNamingInstanceList().get(0); - String httpUrl = NamingServerConstants.HTTP_PREFIX + node.getControl().getHost() - + NamingServerConstants.IP_PORT_SPLIT_CHAR + node.getControl().getPort() - + NamingServerConstants.HTTP_REMOVE_GROUP_SUFFIX; - HashMap params = new HashMap<>(); - params.put(CONSTANT_GROUP, vGroup); - params.put(NamingServerConstants.CONSTANT_UNIT, unitName); - Map header = new HashMap<>(); - header.put(HTTP.CONTENT_TYPE, ContentType.APPLICATION_FORM_URLENCODED.getMimeType()); - try (CloseableHttpResponse closeableHttpResponse = - HttpClientUtil.doGet(httpUrl, params, header, 3000)) { - if (closeableHttpResponse == null - || closeableHttpResponse.getStatusLine().getStatusCode() != 200) { - LOGGER.warn("remove vGroup in old cluster failed"); - return new Result<>(String.valueOf(closeableHttpResponse.getStatusLine().getStatusCode()), - "removing vGroup " + vGroup + " in old cluster " + cluster + " failed"); - } - } catch (IOException e) { - LOGGER.warn("handle removing vGroup in old cluster failed"); - return new Result<>("500", - "handle removing vGroup " + vGroup + " in old cluster " + cluster + " failed"); - } + public Result removeGroup(Unit unit, String vGroup, String clusterName, String namespace, String unitName) { + if (unit != null && !CollectionUtils.isEmpty(unit.getNamingInstanceList())) { + Node node = unit.getNamingInstanceList().get(0); + String httpUrl = NamingServerConstants.HTTP_PREFIX + node.getControl().getHost() + + NamingServerConstants.IP_PORT_SPLIT_CHAR + node.getControl().getPort() + + NamingServerConstants.HTTP_REMOVE_GROUP_SUFFIX; + HashMap params = new HashMap<>(); + params.put(CONSTANT_GROUP, vGroup); + params.put(NamingServerConstants.CONSTANT_UNIT, unitName); + Map header = new HashMap<>(); + header.put(HTTP.CONTENT_TYPE, ContentType.APPLICATION_FORM_URLENCODED.getMimeType()); + try (CloseableHttpResponse closeableHttpResponse = HttpClientUtil.doGet(httpUrl, params, header, 3000)) { + if (closeableHttpResponse == null || closeableHttpResponse.getStatusLine().getStatusCode() != 200) { + LOGGER.warn("remove vGroup in old cluster failed"); + return new Result<>(String.valueOf(closeableHttpResponse.getStatusLine().getStatusCode()), + "removing vGroup " + vGroup + " in old cluster " + clusterName + " failed"); } + LOGGER.info("namespace: {} remove vGroup: {} in new cluster: {} successfully!", namespace, vGroup, + clusterName); + } catch (IOException e) { + LOGGER.warn("handle removing vGroup in old cluster failed"); + return new Result<>("500", + "handle removing vGroup " + vGroup + " in old cluster " + clusterName + " failed"); } } return new Result<>("200", "remove group in old cluster successfully!"); @@ -248,20 +240,21 @@ public boolean registerInstance(NamingServerNode node, String namespace, String ClusterData clusterData = clusterDataHashMap.computeIfAbsent(clusterName, key -> new ClusterData(clusterName, (String)node.getMetadata().get("cluster-type"))); boolean hasChanged = clusterData.registerInstance(node, unitName); + Object mappingObj = node.getMetadata().get(CONSTANT_GROUP); // if extended metadata includes vgroup mapping relationship, add it in clusterData - Optional.ofNullable(node.getMetadata().get(CONSTANT_GROUP)).ifPresent(mappingObj -> { - if (mappingObj instanceof Map) { - Map vGroups = (Map) mappingObj; + if (mappingObj instanceof Map) { + Map vGroups = (Map)mappingObj; + if (!CollectionUtils.isEmpty(vGroups)) { vGroups.forEach((k, v) -> { // In non-raft mode, a unit is one-to-one with a node, and the unitName is stored on the node. // In raft mode, the unitName is equal to the raft-group, so the node's unitName cannot be used. addGroup(namespace, clusterName, StringUtils.isBlank(v) ? unitName : v, k); if (hasChanged) { - notifyClusterChange(k,namespace, clusterName, unitName,node.getTerm()); + notifyClusterChange(k, namespace, clusterName, unitName, node.getTerm()); } }); } - }); + } instanceLiveTable.put( new InetSocketAddress(node.getTransaction().getHost(), node.getTransaction().getPort()), System.currentTimeMillis()); @@ -367,24 +360,26 @@ public void instanceHeartBeatCheck() { } public Result changeGroup(String namespace, String vGroup, String clusterName, String unitName) { - ConcurrentMap namespaceMap = - new ConcurrentHashMap<>(vGroupMap.get(vGroup)); + ConcurrentMap namespaceMap = new ConcurrentHashMap<>(vGroupMap.get(vGroup)); + Set currentNamespaces = namespaceMap.keySet(); + Map> namespaceClusters = new HashMap<>(); + for (String currentNamespace : currentNamespaces) { + namespaceClusters.put(currentNamespace, + new HashSet<>(namespaceMap.get(currentNamespace).getClusterMap().keySet())); + } createGroup(namespace, vGroup, clusterName, unitName); AtomicReference> result = new AtomicReference<>(); - namespaceMap.forEach((currentNamespace, namespaceBO) -> namespaceBO.getClusterMap().forEach((currentCluster, clusterBO) -> { - for (String currentUnitName : clusterBO.getUnitNames()) { - if (StringUtils.isBlank(unitName)) { - if (StringUtils.equalsIgnoreCase(clusterName, currentCluster)) { - continue; - } - result.set(removeGroup(currentNamespace, currentCluster, vGroup, unitName)); - } else { - if (!StringUtils.equalsIgnoreCase(unitName, currentUnitName)) { - result.set(removeGroup(currentNamespace, currentCluster, vGroup, unitName)); - } - } + namespaceClusters.forEach((oldNamespace, clusters) -> { + for (String cluster : clusters) { + Optional.ofNullable(namespaceClusterDataMap.get(oldNamespace)) + .flatMap(map -> Optional.ofNullable(map.get(cluster))).ifPresent(clusterData -> { + if (!CollectionUtils.isEmpty(clusterData.getUnitData())) { + clusterData.getUnitData().forEach((unit, unitData) -> result + .set(removeGroup(unitData, vGroup, cluster, oldNamespace, unitName))); + } + }); } - })); + }); return Optional.ofNullable(result.get()).orElseGet(() -> new Result<>("200", "change vGroup successfully!")); } diff --git a/script/client/conf/registry.conf b/script/client/conf/registry.conf index 4a5329b4881..48f2cd60b46 100644 --- a/script/client/conf/registry.conf +++ b/script/client/conf/registry.conf @@ -16,7 +16,7 @@ # registry { - # file 、nacos 、eureka、redis、zk、consul、etcd3、sofa、custom、raft + # file 、nacos 、eureka、redis、zk、consul、etcd3、sofa、custom、raft、namingserver type = "file" raft { @@ -44,6 +44,11 @@ registry { ##if use Nacos naming meta-data for SLB service registry, specify nacos address pattern rules here #slbPattern = "" } + namingserver { + server-addr = "127.0.0.1:8081" + namespace = "public" + heartbeat-period = 5000 + } eureka { serviceUrl = "http://localhost:8761/eureka" weight = "1" diff --git a/script/client/spring/application.properties b/script/client/spring/application.properties index f74bcbb53bd..1715c373622 100755 --- a/script/client/spring/application.properties +++ b/script/client/spring/application.properties @@ -133,6 +133,9 @@ seata.registry.etcd3.server-addr=http://localhost:2379 seata.registry.eureka.weight=1 seata.registry.eureka.service-url=http://localhost:8761/eureka +seata.registry.namingserver.server-addr=127.0.0.1:8081 +seata.registry.namingserver.namespace=public +seata.registry.namingserver.heartbeat-period=5000 seata.registry.nacos.application=seata-server seata.registry.nacos.server-addr=127.0.0.1:8848 diff --git a/script/client/spring/application.yml b/script/client/spring/application.yml index 951002d5f86..e1a170c7645 100755 --- a/script/client/spring/application.yml +++ b/script/client/spring/application.yml @@ -131,6 +131,10 @@ seata: name: registry: type: file + namingserver: + server-addr: 127.0.0.1:8081 + namespace: public + heartbeat-period: 5000 raft: server-addr: metadata-max-age-ms: 30000 diff --git a/seata-spring-autoconfigure/seata-spring-autoconfigure-core/src/main/java/org/apache/seata/spring/boot/autoconfigure/SeataCoreEnvironmentPostProcessor.java b/seata-spring-autoconfigure/seata-spring-autoconfigure-core/src/main/java/org/apache/seata/spring/boot/autoconfigure/SeataCoreEnvironmentPostProcessor.java index df9478809d5..67bc7bd75ab 100644 --- a/seata-spring-autoconfigure/seata-spring-autoconfigure-core/src/main/java/org/apache/seata/spring/boot/autoconfigure/SeataCoreEnvironmentPostProcessor.java +++ b/seata-spring-autoconfigure/seata-spring-autoconfigure-core/src/main/java/org/apache/seata/spring/boot/autoconfigure/SeataCoreEnvironmentPostProcessor.java @@ -34,6 +34,7 @@ import org.apache.seata.spring.boot.autoconfigure.properties.registry.RegistryEtcd3Properties; import org.apache.seata.spring.boot.autoconfigure.properties.registry.RegistryEurekaProperties; import org.apache.seata.spring.boot.autoconfigure.properties.registry.RegistryNacosProperties; +import org.apache.seata.spring.boot.autoconfigure.properties.registry.RegistryNamingServerProperties; import org.apache.seata.spring.boot.autoconfigure.properties.registry.RegistryProperties; import org.apache.seata.spring.boot.autoconfigure.properties.registry.RegistryRaftProperties; import org.apache.seata.spring.boot.autoconfigure.properties.registry.RegistryRedisProperties; @@ -59,6 +60,7 @@ import static org.apache.seata.spring.boot.autoconfigure.StarterConstants.REGISTRY_ETCD3_PREFIX; import static org.apache.seata.spring.boot.autoconfigure.StarterConstants.REGISTRY_EUREKA_PREFIX; import static org.apache.seata.spring.boot.autoconfigure.StarterConstants.REGISTRY_NACOS_PREFIX; +import static org.apache.seata.spring.boot.autoconfigure.StarterConstants.REGISTRY_NAMINGSERVER_PREFIX; import static org.apache.seata.spring.boot.autoconfigure.StarterConstants.REGISTRY_PREFIX; import static org.apache.seata.spring.boot.autoconfigure.StarterConstants.REGISTRY_RAFT_PREFIX; import static org.apache.seata.spring.boot.autoconfigure.StarterConstants.REGISTRY_REDIS_PREFIX; @@ -100,6 +102,7 @@ public static void init() { PROPERTY_BEAN_MAP.put(REGISTRY_ETCD3_PREFIX, RegistryEtcd3Properties.class); PROPERTY_BEAN_MAP.put(REGISTRY_EUREKA_PREFIX, RegistryEurekaProperties.class); PROPERTY_BEAN_MAP.put(REGISTRY_NACOS_PREFIX, RegistryNacosProperties.class); + PROPERTY_BEAN_MAP.put(REGISTRY_NAMINGSERVER_PREFIX, RegistryNamingServerProperties.class); PROPERTY_BEAN_MAP.put(REGISTRY_REDIS_PREFIX, RegistryRedisProperties.class); PROPERTY_BEAN_MAP.put(REGISTRY_SOFA_PREFIX, RegistrySofaProperties.class); PROPERTY_BEAN_MAP.put(REGISTRY_ZK_PREFIX, RegistryZooKeeperProperties.class); diff --git a/seata-spring-autoconfigure/seata-spring-autoconfigure-core/src/main/java/org/apache/seata/spring/boot/autoconfigure/StarterConstants.java b/seata-spring-autoconfigure/seata-spring-autoconfigure-core/src/main/java/org/apache/seata/spring/boot/autoconfigure/StarterConstants.java index f5fe4fe6721..3d1d7dcce13 100644 --- a/seata-spring-autoconfigure/seata-spring-autoconfigure-core/src/main/java/org/apache/seata/spring/boot/autoconfigure/StarterConstants.java +++ b/seata-spring-autoconfigure/seata-spring-autoconfigure-core/src/main/java/org/apache/seata/spring/boot/autoconfigure/StarterConstants.java @@ -53,6 +53,7 @@ public interface StarterConstants { String REGISTRY_REDIS_PREFIX = REGISTRY_PREFIX + ".redis"; String REGISTRY_ZK_PREFIX = REGISTRY_PREFIX + ".zk"; String REGISTRY_CONSUL_PREFIX = REGISTRY_PREFIX + ".consul"; + String REGISTRY_NAMINGSERVER_PREFIX = REGISTRY_PREFIX + ".namingserver"; String REGISTRY_ETCD3_PREFIX = REGISTRY_PREFIX + ".etcd3"; String REGISTRY_SOFA_PREFIX = REGISTRY_PREFIX + ".sofa"; String REGISTRY_CUSTOM_PREFIX = REGISTRY_PREFIX + ".custom"; @@ -96,4 +97,5 @@ public interface StarterConstants { String SPECIAL_KEY_GROUPLIST = "grouplist"; String SPECIAL_KEY_SERVICE = "service"; String SPECIAL_KEY_VGROUP_MAPPING = "vgroupMapping"; + } diff --git a/seata-spring-autoconfigure/seata-spring-autoconfigure-core/src/main/java/org/apache/seata/spring/boot/autoconfigure/properties/registry/RegistryNamingServerProperties.java b/seata-spring-autoconfigure/seata-spring-autoconfigure-core/src/main/java/org/apache/seata/spring/boot/autoconfigure/properties/registry/RegistryNamingServerProperties.java new file mode 100644 index 00000000000..86dc8577543 --- /dev/null +++ b/seata-spring-autoconfigure/seata-spring-autoconfigure-core/src/main/java/org/apache/seata/spring/boot/autoconfigure/properties/registry/RegistryNamingServerProperties.java @@ -0,0 +1,66 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.seata.spring.boot.autoconfigure.properties.registry; + +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; + +import static org.apache.seata.spring.boot.autoconfigure.StarterConstants.REGISTRY_NAMINGSERVER_PREFIX; + +@Component +@ConfigurationProperties(prefix = REGISTRY_NAMINGSERVER_PREFIX) +public class RegistryNamingServerProperties { + private String cluster = "default"; + private String serverAddr = "127.0.0.1:8081"; + private String namespace = "public"; + + private int heartbeatPeriod = 5000; + + public String getCluster() { + return cluster; + } + + public RegistryNamingServerProperties setCluster(String cluster) { + this.cluster = cluster; + return this; + } + + public String getServerAddr() { + return serverAddr; + } + + public RegistryNamingServerProperties setServerAddr(String serverAddr) { + this.serverAddr = serverAddr; + return this; + } + + public String getNamespace() { + return namespace; + } + + public void setNamespace(String namespace) { + this.namespace = namespace; + } + + public int getHeartbeatPeriod() { + return heartbeatPeriod; + } + + public void setHeartbeatPeriod(int heartbeatPeriod) { + this.heartbeatPeriod = heartbeatPeriod; + } +} diff --git a/server/src/main/java/org/apache/seata/server/Server.java b/server/src/main/java/org/apache/seata/server/Server.java index 8289ded6b8d..4f4de537cca 100644 --- a/server/src/main/java/org/apache/seata/server/Server.java +++ b/server/src/main/java/org/apache/seata/server/Server.java @@ -24,6 +24,7 @@ import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; +import javax.annotation.Resource; import org.apache.seata.common.XID; import org.apache.seata.common.holder.ObjectHolder; import org.apache.seata.common.metadata.Node; @@ -41,6 +42,8 @@ import org.apache.seata.server.session.SessionHolder; import org.apache.seata.server.store.StoreConfig; import org.apache.seata.server.store.VGroupMappingStoreManager; +import org.apache.seata.spring.boot.autoconfigure.properties.registry.RegistryNamingServerProperties; +import org.apache.seata.spring.boot.autoconfigure.properties.registry.RegistryProperties; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; @@ -48,15 +51,11 @@ import org.springframework.core.env.ConfigurableEnvironment; import org.springframework.core.env.EnumerablePropertySource; import org.springframework.core.env.PropertySource; +import org.springframework.stereotype.Component; import org.springframework.web.context.support.GenericWebApplicationContext; -import static org.apache.seata.common.ConfigurationKeys.CLUSTER_NAME_KEY; -import static org.apache.seata.common.ConfigurationKeys.FILE_CONFIG_SPLIT_CHAR; -import static org.apache.seata.common.ConfigurationKeys.FILE_ROOT_REGISTRY; -import static org.apache.seata.common.ConfigurationKeys.FILE_ROOT_TYPE; import static org.apache.seata.common.ConfigurationKeys.META_PREFIX; -import static org.apache.seata.common.ConfigurationKeys.NAMESPACE_KEY; import static org.apache.seata.common.ConfigurationKeys.NAMING_SERVER; import static org.apache.seata.common.Constants.OBJECT_KEY_SPRING_APPLICATION_CONTEXT; import static org.apache.seata.common.Constants.OBJECT_KEY_SPRING_CONFIGURABLE_ENVIRONMENT; @@ -66,24 +65,31 @@ /** * The type Server. */ +@Component("seataServer") public class Server { private static final Logger LOGGER = LoggerFactory.getLogger(Server.class); - protected static final ScheduledExecutorService EXECUTOR_SERVICE = new ScheduledThreadPoolExecutor(1, new NamedThreadFactory("scheduledExcuter", 1, true)); + protected static volatile ScheduledExecutorService EXECUTOR_SERVICE; - public static void metadataInit() { + @Resource + RegistryNamingServerProperties registryNamingServerProperties; + + @Resource + RegistryProperties registryProperties; + + public void metadataInit() { VGroupMappingStoreManager vGroupMappingStoreManager = SessionHolder.getRootVGroupMappingManager(); - if (StringUtils.equals(ConfigurationFactory.getInstance().getConfig(FILE_ROOT_REGISTRY - + FILE_CONFIG_SPLIT_CHAR + FILE_ROOT_TYPE), NAMING_SERVER)) { + if (StringUtils.equals(registryProperties.getType(), NAMING_SERVER)) { + EXECUTOR_SERVICE = new ScheduledThreadPoolExecutor(1, new NamedThreadFactory("scheduledExcuter", 1, true)); ConfigurableEnvironment environment = (ConfigurableEnvironment) ObjectHolder.INSTANCE.getObject(OBJECT_KEY_SPRING_CONFIGURABLE_ENVIRONMENT); // load node properties Instance instance = Instance.getInstance(); // load namespace - String namespace = environment.getProperty(NAMESPACE_KEY, "public"); + String namespace = registryNamingServerProperties.getNamespace(); instance.setNamespace(namespace); // load cluster name - String clusterName = environment.getProperty(CLUSTER_NAME_KEY, "default"); + String clusterName = registryNamingServerProperties.getCluster(); instance.setClusterName(clusterName); // load cluster type @@ -109,17 +115,18 @@ public static void metadataInit() { } } } - // load vgroup mapping relationship instance.addMetadata("vGroup", vGroupMappingStoreManager.loadVGroups()); + + EXECUTOR_SERVICE.scheduleAtFixedRate(() -> { + try { + vGroupMappingStoreManager.notifyMapping(); + } catch (Exception e) { + LOGGER.error("Naming server register Exception", e); + } + }, registryNamingServerProperties.getHeartbeatPeriod(), registryNamingServerProperties.getHeartbeatPeriod(), TimeUnit.MILLISECONDS); + ServerRunner.addDisposable(EXECUTOR_SERVICE::shutdown); } - EXECUTOR_SERVICE.scheduleAtFixedRate(() -> { - try { - vGroupMappingStoreManager.notifyMapping(); - } catch (Exception e) { - LOGGER.error("Naming server register Exception", e); - } - }, 0, 5000, TimeUnit.MILLISECONDS); } @@ -128,7 +135,7 @@ public static void metadataInit() { * * @param args the input arguments */ - public static void start(String[] args) { + public void start(String[] args) { //initialize the parameter parser //Note that the parameter parser should always be the first line to execute. //Because, here we need to parse the parameters needed for startup. @@ -172,10 +179,9 @@ public static void start(String[] args) { coordinator.init(); nettyRemotingServer.setHandler(coordinator); + metadataInit(); // let ServerRunner do destroy instead ShutdownHook, see https://github.com/seata/seata/issues/4028 ServerRunner.addDisposable(coordinator); - metadataInit(); - nettyRemotingServer.init(); } } diff --git a/server/src/main/java/org/apache/seata/server/ServerRunner.java b/server/src/main/java/org/apache/seata/server/ServerRunner.java index 437f427895e..a48c7379fdf 100644 --- a/server/src/main/java/org/apache/seata/server/ServerRunner.java +++ b/server/src/main/java/org/apache/seata/server/ServerRunner.java @@ -19,6 +19,7 @@ import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; +import javax.annotation.Resource; import org.apache.seata.core.rpc.Disposable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -53,11 +54,14 @@ public static void addDisposable(Disposable disposable) { DISPOSABLE_LIST.add(disposable); } + @Resource + Server seataServer; + @Override public void run(String... args) { try { long start = System.currentTimeMillis(); - Server.start(args); + seataServer.start(args); started = true; long cost = System.currentTimeMillis() - start; diff --git a/server/src/main/java/org/apache/seata/server/storage/db/store/DataBaseVGroupMappingStoreManager.java b/server/src/main/java/org/apache/seata/server/storage/db/store/DataBaseVGroupMappingStoreManager.java index 6389168daef..d83ecf34c37 100644 --- a/server/src/main/java/org/apache/seata/server/storage/db/store/DataBaseVGroupMappingStoreManager.java +++ b/server/src/main/java/org/apache/seata/server/storage/db/store/DataBaseVGroupMappingStoreManager.java @@ -16,12 +16,12 @@ */ package org.apache.seata.server.storage.db.store; +import org.apache.seata.common.ConfigurationKeys; import org.apache.seata.common.loader.EnhancedServiceLoader; import org.apache.seata.common.loader.LoadLevel; import org.apache.seata.common.metadata.namingserver.Instance; import org.apache.seata.config.Configuration; import org.apache.seata.config.ConfigurationFactory; -import org.apache.seata.core.constants.ConfigurationKeys; import org.apache.seata.core.store.MappingDO; import org.apache.seata.core.store.db.DataSourceProvider; import org.apache.seata.server.store.VGroupMappingStoreManager; diff --git a/server/src/main/java/org/apache/seata/server/storage/db/store/VGroupMappingDataBaseDAO.java b/server/src/main/java/org/apache/seata/server/storage/db/store/VGroupMappingDataBaseDAO.java index ed2d68d6354..84fea262d57 100644 --- a/server/src/main/java/org/apache/seata/server/storage/db/store/VGroupMappingDataBaseDAO.java +++ b/server/src/main/java/org/apache/seata/server/storage/db/store/VGroupMappingDataBaseDAO.java @@ -42,7 +42,7 @@ public class VGroupMappingDataBaseDAO { private static final Logger LOGGER = LoggerFactory.getLogger(VGroupMappingDataBaseDAO.class); - protected DataSource vGroupMappingDataSource = null; + protected DataSource vGroupMappingDataSource; protected final String vMapping; @@ -98,7 +98,6 @@ public boolean deleteMappingDOByVGroup(String vGroup) { PreparedStatement ps = null; try { conn = vGroupMappingDataSource.getConnection(); - conn.setAutoCommit(true); ps = conn.prepareStatement(sql); ps.setString(1, vGroup); ps.setString(2, instance.getClusterName()); diff --git a/server/src/main/java/org/apache/seata/server/storage/redis/store/RedisVGroupMappingStoreManager.java b/server/src/main/java/org/apache/seata/server/storage/redis/store/RedisVGroupMappingStoreManager.java index 470f39cde43..1367ad281f3 100644 --- a/server/src/main/java/org/apache/seata/server/storage/redis/store/RedisVGroupMappingStoreManager.java +++ b/server/src/main/java/org/apache/seata/server/storage/redis/store/RedisVGroupMappingStoreManager.java @@ -51,8 +51,13 @@ public boolean removeVGroup(String vGroup) { Instance instance = Instance.getInstance(); String namespace = REDIS_PREFIX + instance.getNamespace(); try (Jedis jedis = JedisPooledFactory.getJedisInstance()) { - jedis.hdel(namespace, vGroup); - return true; + String currentVgroup = jedis.hget(namespace, vGroup); + if (StringUtils.equalsIgnoreCase(currentVgroup, instance.getClusterName())) { + jedis.hdel(namespace, vGroup); + return true; + } else { + return false; + } } catch (Exception ex) { throw new RedisException(ex); } diff --git a/server/src/main/java/org/apache/seata/server/store/VGroupMappingStoreManager.java b/server/src/main/java/org/apache/seata/server/store/VGroupMappingStoreManager.java index cf45795a7b8..d4ce6a5412f 100644 --- a/server/src/main/java/org/apache/seata/server/store/VGroupMappingStoreManager.java +++ b/server/src/main/java/org/apache/seata/server/store/VGroupMappingStoreManager.java @@ -24,6 +24,7 @@ import java.net.InetSocketAddress; import java.util.HashMap; +import java.util.Map; public interface VGroupMappingStoreManager { /** @@ -55,12 +56,12 @@ default HashMap readVGroups() { * notify mapping relationship to all namingserver nodes */ default void notifyMapping() { - Instance instance = Instance.getInstance(); - instance.addMetadata("vGroup", this.readVGroups()); + Map map = this.readVGroups(); + instance.addMetadata("vGroup", map); try { InetSocketAddress address = new InetSocketAddress(XID.getIpAddress(), XID.getPort()); - for (RegistryService registryService : MultiRegistryFactory.getInstances()) { + for (RegistryService registryService : MultiRegistryFactory.getInstances()) { registryService.register(address); } } catch (Exception e) { diff --git a/server/src/main/resources/application.example.yml b/server/src/main/resources/application.example.yml index 0a7897ab930..09360ccbaf7 100644 --- a/server/src/main/resources/application.example.yml +++ b/server/src/main/resources/application.example.yml @@ -80,12 +80,12 @@ seata: type: file preferred-networks: 30.240.* metadata: - weight: 1 + weight: 100 namingserver: - server-addr: 127.0.0.1:8080 + server-addr: 127.0.0.1:8081 cluster: default namespace: public - heartbeat-period: 1000 + heartbeat-period: 5000 nacos: application: seata-server server-addr: 127.0.0.1:8848 From 256c4a32e3eb9b934a2a0f40b140afa1b1ec2525 Mon Sep 17 00:00:00 2001 From: jimin Date: Tue, 27 Aug 2024 11:21:10 +0800 Subject: [PATCH 7/8] optimize: upgrade axios to 1.7.4 (#6784) --- changes/en-us/2.x.md | 1 + changes/zh-cn/2.x.md | 1 + .../main/resources/static/console-fe/package-lock.json | 10 +++++----- .../src/main/resources/static/console-fe/package.json | 2 +- 4 files changed, 8 insertions(+), 6 deletions(-) diff --git a/changes/en-us/2.x.md b/changes/en-us/2.x.md index 3de47dd8d0a..a02f735c6b5 100644 --- a/changes/en-us/2.x.md +++ b/changes/en-us/2.x.md @@ -66,6 +66,7 @@ Add changes here for all PR submitted to the 2.x branch. - [[#6768](https://github.com/apache/incubator-seata/pull/6768)] report the tcc fence transaction isolation level - [[#6770](https://github.com/apache/incubator-seata/pull/6770)] Automatic deletion of namingserver vgroup through Caffeine map - [[#6780](https://github.com/apache/incubator-seata/pull/6780)] optimize the reflection operation in class `SerializerServiceLoader` +- [[#6784](https://github.com/apache/incubator-seata/pull/6784)] upgrade axios to 1.7.4 ### refactor: diff --git a/changes/zh-cn/2.x.md b/changes/zh-cn/2.x.md index 2b440e474b2..30621201bba 100644 --- a/changes/zh-cn/2.x.md +++ b/changes/zh-cn/2.x.md @@ -67,6 +67,7 @@ - [[#6768](https://github.com/apache/incubator-seata/pull/6768)] 上报tcc fence事务隔离级别 - [[#6770](https://github.com/apache/incubator-seata/pull/6770)] 通过caffeine map支持namingserver事务分组的过期删除 - [[#6780](https://github.com/apache/incubator-seata/pull/6780)] 优化类 `SerializerServiceLoader` 中的反射操作 +- [[#6784](https://github.com/apache/incubator-seata/pull/6784)] 升级 axios 至 1.7.4 版本 ### refactor: diff --git a/console/src/main/resources/static/console-fe/package-lock.json b/console/src/main/resources/static/console-fe/package-lock.json index e2156035b36..25a6f565896 100644 --- a/console/src/main/resources/static/console-fe/package-lock.json +++ b/console/src/main/resources/static/console-fe/package-lock.json @@ -14,7 +14,7 @@ "@alicloud/console-components-app-layout": "^1.1.4", "@alicloud/console-components-console-menu": "^1.2.12", "@babel/traverse": "^7.23.7", - "axios": "^1.6.6", + "axios": "^1.7.4", "browserify-sign": "^4.2.2", "decode-uri-component": "^0.4.1", "history": "^4.10.1", @@ -4191,11 +4191,11 @@ } }, "node_modules/axios": { - "version": "1.6.7", - "resolved": "https://registry.npmmirror.com/axios/-/axios-1.6.7.tgz", - "integrity": "sha512-/hDJGff6/c7u0hDkvkGxR/oy6CbCs8ziCsC7SqmhjfozqiJGc8Z11wrv9z9lYfY4K8l+H9TpjcMDX0xOZmx+RA==", + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.4.tgz", + "integrity": "sha512-DukmaFRnY6AzAALSH4J2M3k6PkaC+MfaAGdEERRWcC9q3/TWQwLpHR8ZRLKTdQ3aBDL64EdluRDjJqKw+BPZEw==", "dependencies": { - "follow-redirects": "^1.15.4", + "follow-redirects": "^1.15.6", "form-data": "^4.0.0", "proxy-from-env": "^1.1.0" } diff --git a/console/src/main/resources/static/console-fe/package.json b/console/src/main/resources/static/console-fe/package.json index 8594c7949fb..83867a212cf 100644 --- a/console/src/main/resources/static/console-fe/package.json +++ b/console/src/main/resources/static/console-fe/package.json @@ -79,7 +79,7 @@ "@alicloud/console-components-app-layout": "^1.1.4", "@alicloud/console-components-console-menu": "^1.2.12", "@babel/traverse": "^7.23.7", - "axios": "^1.6.6", + "axios": "^1.7.4", "browserify-sign": "^4.2.2", "decode-uri-component": "^0.4.1", "history": "^4.10.1", From 4aa5d57d51131764388c9539b803f7e52cb47f0b Mon Sep 17 00:00:00 2001 From: jimin Date: Tue, 27 Aug 2024 16:23:40 +0800 Subject: [PATCH 8/8] optimize: upgrade elliptic to 6.5.7 (#6787) --- changes/en-us/2.x.md | 1 + changes/zh-cn/2.x.md | 1 + .../static/console-fe/package-lock.json | 325 +++++++++++------- .../resources/static/console-fe/package.json | 1 + 4 files changed, 205 insertions(+), 123 deletions(-) diff --git a/changes/en-us/2.x.md b/changes/en-us/2.x.md index a02f735c6b5..4829e0974c3 100644 --- a/changes/en-us/2.x.md +++ b/changes/en-us/2.x.md @@ -67,6 +67,7 @@ Add changes here for all PR submitted to the 2.x branch. - [[#6770](https://github.com/apache/incubator-seata/pull/6770)] Automatic deletion of namingserver vgroup through Caffeine map - [[#6780](https://github.com/apache/incubator-seata/pull/6780)] optimize the reflection operation in class `SerializerServiceLoader` - [[#6784](https://github.com/apache/incubator-seata/pull/6784)] upgrade axios to 1.7.4 +- [[#6787](https://github.com/apache/incubator-seata/pull/6787)] upgrade elliptic to 6.5.7 ### refactor: diff --git a/changes/zh-cn/2.x.md b/changes/zh-cn/2.x.md index 30621201bba..9f53d34f537 100644 --- a/changes/zh-cn/2.x.md +++ b/changes/zh-cn/2.x.md @@ -68,6 +68,7 @@ - [[#6770](https://github.com/apache/incubator-seata/pull/6770)] 通过caffeine map支持namingserver事务分组的过期删除 - [[#6780](https://github.com/apache/incubator-seata/pull/6780)] 优化类 `SerializerServiceLoader` 中的反射操作 - [[#6784](https://github.com/apache/incubator-seata/pull/6784)] 升级 axios 至 1.7.4 版本 +- [[#6787](https://github.com/apache/incubator-seata/pull/6787)] 升级 elliptic 至 6.5.7 版本 ### refactor: diff --git a/console/src/main/resources/static/console-fe/package-lock.json b/console/src/main/resources/static/console-fe/package-lock.json index 25a6f565896..7f5fa44a754 100644 --- a/console/src/main/resources/static/console-fe/package-lock.json +++ b/console/src/main/resources/static/console-fe/package-lock.json @@ -17,6 +17,7 @@ "axios": "^1.7.4", "browserify-sign": "^4.2.2", "decode-uri-component": "^0.4.1", + "elliptic": "^6.5.7", "history": "^4.10.1", "jquery": "^3.7.1", "loader-utils": "^3.2.1", @@ -5144,7 +5145,7 @@ }, "node_modules/cli-truncate": { "version": "4.0.0", - "resolved": "https://registry.npmmirror.com/cli-truncate/-/cli-truncate-4.0.0.tgz", + "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-4.0.0.tgz", "integrity": "sha512-nPdaFdQ0h/GEigbPClz11D0v/ZJEwxmeVZGeMo3Z5StPtUTkA9o1lD6QwoirYiSDzbcwn2XcjwmCp68W1IS4TA==", "dev": true, "dependencies": { @@ -5153,27 +5154,33 @@ }, "engines": { "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/cli-truncate/node_modules/ansi-regex": { "version": "6.0.1", - "resolved": "https://registry.npmmirror.com/ansi-regex/-/ansi-regex-6.0.1.tgz", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", "dev": true, "engines": { "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" } }, "node_modules/cli-truncate/node_modules/emoji-regex": { - "version": "10.3.0", - "resolved": "https://registry.npmmirror.com/emoji-regex/-/emoji-regex-10.3.0.tgz", - "integrity": "sha512-QpLs9D9v9kArv4lfDEgg1X/gN5XLnf/A6l9cs8SPZLRZR3ZkY9+kwIQTxm+fsSej5UMYGE8fdoaZVIBlqG0XTw==", + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.4.0.tgz", + "integrity": "sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw==", "dev": true }, "node_modules/cli-truncate/node_modules/string-width": { - "version": "7.1.0", - "resolved": "https://registry.npmmirror.com/string-width/-/string-width-7.1.0.tgz", - "integrity": "sha512-SEIJCWiX7Kg4c129n48aDRwLbFb2LJmXXFrWBG4NGaRtMQ3myKPKbwrD1BKqQn74oCoNMBVrfDEr5M9YxCsrkw==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", "dev": true, "dependencies": { "emoji-regex": "^10.3.0", @@ -5182,11 +5189,14 @@ }, "engines": { "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/cli-truncate/node_modules/strip-ansi": { "version": "7.1.0", - "resolved": "https://registry.npmmirror.com/strip-ansi/-/strip-ansi-7.1.0.tgz", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", "dev": true, "dependencies": { @@ -5194,6 +5204,9 @@ }, "engines": { "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" } }, "node_modules/cli-width": { @@ -6003,9 +6016,9 @@ "integrity": "sha512-vjAczensTgRcqDERK0SR2XMwsF/tSvnvlv6VcF2GIhg6Sx4yOIt/irsr1RDJsKiIyBzJDpCoXiWWq28MqH2cnQ==" }, "node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmmirror.com/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.6.tgz", + "integrity": "sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==", "dependencies": { "ms": "2.1.2" }, @@ -6809,9 +6822,9 @@ "integrity": "sha512-1PpuqJUFWoXZ1E54m8bsLPVYwIVCRzvaL+n5cjigGga4z854abDnFRc+cTa2th4S79kyGqya/1xoR7h+Y5G5lg==" }, "node_modules/elliptic": { - "version": "6.5.6", - "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.6.tgz", - "integrity": "sha512-mpzdtpeCLuS3BmE3pO3Cpp5bbjlOPY2Q0PgoF+Od1XZrHLYI28Xe3ossCmYCQt11FQKEYd9+PF8jymTvtWJSHQ==", + "version": "6.5.7", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.7.tgz", + "integrity": "sha512-ESVCtTwiA+XhY3wyh24QqRGBoP3rEdDUl3EDUUo9tft074fi19IrdpH7hLCMMP3CIj7jb3W96rn8lt/BqIlt5Q==", "dependencies": { "bn.js": "^4.11.9", "brorand": "^1.1.0", @@ -6921,6 +6934,18 @@ "node": ">=4" } }, + "node_modules/environment": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/environment/-/environment-1.1.0.tgz", + "integrity": "sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q==", + "dev": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/err-code": { "version": "2.0.3", "resolved": "https://registry.npmmirror.com/err-code/-/err-code-2.0.3.tgz", @@ -8596,7 +8621,7 @@ }, "node_modules/eventemitter3": { "version": "5.0.1", - "resolved": "https://registry.npmmirror.com/eventemitter3/-/eventemitter3-5.0.1.tgz", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==", "dev": true }, @@ -9487,11 +9512,14 @@ }, "node_modules/get-east-asian-width": { "version": "1.2.0", - "resolved": "https://registry.npmmirror.com/get-east-asian-width/-/get-east-asian-width-1.2.0.tgz", + "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.2.0.tgz", "integrity": "sha512-2nk+7SIVb14QrgXFHcm84tD4bKQz0RxPuMT8Ag5KPOq7J5fEmAg0UbXdTOSHqNuHSU28k55qnceesxXRZGzKWA==", "dev": true, "engines": { "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/get-intrinsic": { @@ -10721,11 +10749,14 @@ }, "node_modules/is-fullwidth-code-point": { "version": "4.0.0", - "resolved": "https://registry.npmmirror.com/is-fullwidth-code-point/-/is-fullwidth-code-point-4.0.0.tgz", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-4.0.0.tgz", "integrity": "sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==", "dev": true, "engines": { "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/is-generator-function": { @@ -11204,12 +11235,15 @@ } }, "node_modules/lilconfig": { - "version": "3.0.0", - "resolved": "https://registry.npmmirror.com/lilconfig/-/lilconfig-3.0.0.tgz", - "integrity": "sha512-K2U4W2Ff5ibV7j7ydLr+zLAkIg5JJ4lPn1Ltsdt+Tz/IjQ8buJ55pZAxoP34lqIiwtF9iAvtLv3JGv7CAyAg+g==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.2.tgz", + "integrity": "sha512-eop+wDAvpItUys0FWkHIKeC9ybYrTGbU41U5K7+bttZZeohvnY7M9dZ5kB21GNWiFT2q1OoPTvncPCgSOVO5ow==", "dev": true, "engines": { "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antonk52" } }, "node_modules/lines-and-columns": { @@ -11218,27 +11252,30 @@ "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==" }, "node_modules/lint-staged": { - "version": "15.2.2", - "resolved": "https://registry.npmmirror.com/lint-staged/-/lint-staged-15.2.2.tgz", - "integrity": "sha512-TiTt93OPh1OZOsb5B7k96A/ATl2AjIZo+vnzFZ6oHK5FuTk63ByDtxGQpHm+kFETjEWqgkF95M8FRXKR/LEBcw==", - "dev": true, - "dependencies": { - "chalk": "5.3.0", - "commander": "11.1.0", - "debug": "4.3.4", - "execa": "8.0.1", - "lilconfig": "3.0.0", - "listr2": "8.0.1", - "micromatch": "4.0.5", - "pidtree": "0.6.0", - "string-argv": "0.3.2", - "yaml": "2.3.4" + "version": "15.2.9", + "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-15.2.9.tgz", + "integrity": "sha512-BZAt8Lk3sEnxw7tfxM7jeZlPRuT4M68O0/CwZhhaw6eeWu0Lz5eERE3m386InivXB64fp/mDID452h48tvKlRQ==", + "dev": true, + "dependencies": { + "chalk": "~5.3.0", + "commander": "~12.1.0", + "debug": "~4.3.6", + "execa": "~8.0.1", + "lilconfig": "~3.1.2", + "listr2": "~8.2.4", + "micromatch": "~4.0.7", + "pidtree": "~0.6.0", + "string-argv": "~0.3.2", + "yaml": "~2.5.0" }, "bin": { "lint-staged": "bin/lint-staged.js" }, "engines": { "node": ">=18.12.0" + }, + "funding": { + "url": "https://opencollective.com/lint-staged" } }, "node_modules/lint-staged/node_modules/chalk": { @@ -11251,34 +11288,37 @@ } }, "node_modules/lint-staged/node_modules/commander": { - "version": "11.1.0", - "resolved": "https://registry.npmmirror.com/commander/-/commander-11.1.0.tgz", - "integrity": "sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==", + "version": "12.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-12.1.0.tgz", + "integrity": "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==", "dev": true, "engines": { - "node": ">=16" + "node": ">=18" } }, "node_modules/lint-staged/node_modules/yaml": { - "version": "2.3.4", - "resolved": "https://registry.npmmirror.com/yaml/-/yaml-2.3.4.tgz", - "integrity": "sha512-8aAvwVUSHpfEqTQ4w/KMlf3HcRdt50E5ODIQJBw1fQ5RL34xabzxtUlzTXVqc4rkZsPbvrXKWnABCD7kWSmocA==", + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.5.0.tgz", + "integrity": "sha512-2wWLbGbYDiSqqIKoPjar3MPgB94ErzCtrNE1FdqGuaO0pi2JGjmE8aW8TDZwzU7vuxcGRdL/4gPQwQ7hD5AMSw==", "dev": true, + "bin": { + "yaml": "bin.mjs" + }, "engines": { "node": ">= 14" } }, "node_modules/listr2": { - "version": "8.0.1", - "resolved": "https://registry.npmmirror.com/listr2/-/listr2-8.0.1.tgz", - "integrity": "sha512-ovJXBXkKGfq+CwmKTjluEqFi3p4h8xvkxGQQAQan22YCgef4KZ1mKGjzfGh6PL6AW5Csw0QiQPNuQyH+6Xk3hA==", + "version": "8.2.4", + "resolved": "https://registry.npmjs.org/listr2/-/listr2-8.2.4.tgz", + "integrity": "sha512-opevsywziHd3zHCVQGAj8zu+Z3yHNkkoYhWIGnq54RrCVwLz0MozotJEDnKsIBLvkfLGN6BLOyAeRrYI0pKA4g==", "dev": true, "dependencies": { "cli-truncate": "^4.0.0", "colorette": "^2.0.20", "eventemitter3": "^5.0.1", - "log-update": "^6.0.0", - "rfdc": "^1.3.0", + "log-update": "^6.1.0", + "rfdc": "^1.4.1", "wrap-ansi": "^9.0.0" }, "engines": { @@ -11430,66 +11470,81 @@ "dev": true }, "node_modules/log-update": { - "version": "6.0.0", - "resolved": "https://registry.npmmirror.com/log-update/-/log-update-6.0.0.tgz", - "integrity": "sha512-niTvB4gqvtof056rRIrTZvjNYE4rCUzO6X/X+kYjd7WFxXeJ0NwEFnRxX6ehkvv3jTwrXnNdtAak5XYZuIyPFw==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/log-update/-/log-update-6.1.0.tgz", + "integrity": "sha512-9ie8ItPR6tjY5uYJh8K/Zrv/RMZ5VOlOWvtZdEHYSTFKZfIBPQa9tOAEeAWhd+AnIneLJ22w5fjOYtoutpWq5w==", "dev": true, "dependencies": { - "ansi-escapes": "^6.2.0", - "cli-cursor": "^4.0.0", - "slice-ansi": "^7.0.0", + "ansi-escapes": "^7.0.0", + "cli-cursor": "^5.0.0", + "slice-ansi": "^7.1.0", "strip-ansi": "^7.1.0", "wrap-ansi": "^9.0.0" }, "engines": { "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/log-update/node_modules/ansi-escapes": { - "version": "6.2.0", - "resolved": "https://registry.npmmirror.com/ansi-escapes/-/ansi-escapes-6.2.0.tgz", - "integrity": "sha512-kzRaCqXnpzWs+3z5ABPQiVke+iq0KXkHo8xiWV4RPTi5Yli0l97BEQuhXV1s7+aSU/fu1kUuxgS4MsQ0fRuygw==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-7.0.0.tgz", + "integrity": "sha512-GdYO7a61mR0fOlAsvC9/rIHf7L96sBc6dEWzeOu+KAea5bZyQRPIpojrVoI4AXGJS/ycu/fBTdLrUkA4ODrvjw==", "dev": true, "dependencies": { - "type-fest": "^3.0.0" + "environment": "^1.0.0" }, "engines": { - "node": ">=14.16" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/log-update/node_modules/ansi-regex": { "version": "6.0.1", - "resolved": "https://registry.npmmirror.com/ansi-regex/-/ansi-regex-6.0.1.tgz", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", "dev": true, "engines": { "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" } }, "node_modules/log-update/node_modules/ansi-styles": { "version": "6.2.1", - "resolved": "https://registry.npmmirror.com/ansi-styles/-/ansi-styles-6.2.1.tgz", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", "dev": true, "engines": { "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, "node_modules/log-update/node_modules/cli-cursor": { - "version": "4.0.0", - "resolved": "https://registry.npmmirror.com/cli-cursor/-/cli-cursor-4.0.0.tgz", - "integrity": "sha512-VGtlMu3x/4DOtIUwEkRezxUZ2lBacNJCHash0N0WeZDBS+7Ux1dm3XWAgWYxLJFMMdOeXMHXorshEFhbMSGelg==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-5.0.0.tgz", + "integrity": "sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==", "dev": true, "dependencies": { - "restore-cursor": "^4.0.0" + "restore-cursor": "^5.0.0" }, "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/log-update/node_modules/is-fullwidth-code-point": { "version": "5.0.0", - "resolved": "https://registry.npmmirror.com/is-fullwidth-code-point/-/is-fullwidth-code-point-5.0.0.tgz", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-5.0.0.tgz", "integrity": "sha512-OVa3u9kkBbw7b8Xw5F9P+D/T9X+Z4+JruYVNapTjPYZYUznQ5YfWeFkOj606XYYW8yugTfC8Pj0hYqvi4ryAhA==", "dev": true, "dependencies": { @@ -11497,51 +11552,45 @@ }, "engines": { "node": ">=18" - } - }, - "node_modules/log-update/node_modules/mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmmirror.com/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", - "dev": true, - "engines": { - "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/log-update/node_modules/onetime": { - "version": "5.1.2", - "resolved": "https://registry.npmmirror.com/onetime/-/onetime-5.1.2.tgz", - "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-7.0.0.tgz", + "integrity": "sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==", "dev": true, "dependencies": { - "mimic-fn": "^2.1.0" + "mimic-function": "^5.0.0" }, "engines": { - "node": ">=6" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/log-update/node_modules/restore-cursor": { - "version": "4.0.0", - "resolved": "https://registry.npmmirror.com/restore-cursor/-/restore-cursor-4.0.0.tgz", - "integrity": "sha512-I9fPXU9geO9bHOt9pHHOhOkYerIMsmVaWB0rA2AI9ERh/+x/i7MV5HKBNrg+ljO5eoPVgCcnFuRjJ9uH6I/3eg==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-5.1.0.tgz", + "integrity": "sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==", "dev": true, "dependencies": { - "onetime": "^5.1.0", - "signal-exit": "^3.0.2" + "onetime": "^7.0.0", + "signal-exit": "^4.1.0" }, "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/log-update/node_modules/signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmmirror.com/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true - }, "node_modules/log-update/node_modules/slice-ansi": { "version": "7.1.0", - "resolved": "https://registry.npmmirror.com/slice-ansi/-/slice-ansi-7.1.0.tgz", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-7.1.0.tgz", "integrity": "sha512-bSiSngZ/jWeX93BqeIAbImyTbEihizcwNjFoRUIY/T1wWQsfsm2Vw1agPKylXvQTU7iASGdHhyqRlqQzfz+Htg==", "dev": true, "dependencies": { @@ -11550,11 +11599,14 @@ }, "engines": { "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" } }, "node_modules/log-update/node_modules/strip-ansi": { "version": "7.1.0", - "resolved": "https://registry.npmmirror.com/strip-ansi/-/strip-ansi-7.1.0.tgz", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", "dev": true, "dependencies": { @@ -11562,15 +11614,9 @@ }, "engines": { "node": ">=12" - } - }, - "node_modules/log-update/node_modules/type-fest": { - "version": "3.13.1", - "resolved": "https://registry.npmmirror.com/type-fest/-/type-fest-3.13.1.tgz", - "integrity": "sha512-tLq3bSNx+xSpwvAJnzrK0Ep5CLNWjvFTOp71URMaAEWBfRb9nnJiBoUe0tF8bI4ZFO3omgBR6NvnbzVUT3Ly4g==", - "dev": true, - "engines": { - "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" } }, "node_modules/loose-envify": { @@ -12010,12 +12056,12 @@ } }, "node_modules/micromatch": { - "version": "4.0.5", - "resolved": "https://registry.npmmirror.com/micromatch/-/micromatch-4.0.5.tgz", - "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", "dev": true, "dependencies": { - "braces": "^3.0.2", + "braces": "^3.0.3", "picomatch": "^2.3.1" }, "engines": { @@ -12081,6 +12127,18 @@ "node": ">=12" } }, + "node_modules/mimic-function": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/mimic-function/-/mimic-function-5.0.1.tgz", + "integrity": "sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==", + "dev": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/min-document": { "version": "2.19.0", "resolved": "https://registry.npmmirror.com/min-document/-/min-document-2.19.0.tgz", @@ -15303,9 +15361,9 @@ } }, "node_modules/rfdc": { - "version": "1.3.1", - "resolved": "https://registry.npmmirror.com/rfdc/-/rfdc-1.3.1.tgz", - "integrity": "sha512-r5a3l5HzYlIC68TpmYKlxWjmOP6wiPJ1vWv2HeLhNsRZMrCkxeqxiHlQ21oXmQ4F3SiryXBHhAD7JZqvOJjFmg==", + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz", + "integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==", "dev": true }, "node_modules/rimraf": { @@ -16028,7 +16086,7 @@ }, "node_modules/slice-ansi": { "version": "5.0.0", - "resolved": "https://registry.npmmirror.com/slice-ansi/-/slice-ansi-5.0.0.tgz", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-5.0.0.tgz", "integrity": "sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ==", "dev": true, "dependencies": { @@ -16037,15 +16095,21 @@ }, "engines": { "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" } }, "node_modules/slice-ansi/node_modules/ansi-styles": { "version": "6.2.1", - "resolved": "https://registry.npmmirror.com/ansi-styles/-/ansi-styles-6.2.1.tgz", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", "dev": true, "engines": { "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, "node_modules/smart-buffer": { @@ -19479,7 +19543,7 @@ }, "node_modules/wrap-ansi": { "version": "9.0.0", - "resolved": "https://registry.npmmirror.com/wrap-ansi/-/wrap-ansi-9.0.0.tgz", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.0.tgz", "integrity": "sha512-G8ura3S+3Z2G+mkgNRq8dqaFZAuxfsxpBB8OCTGRTCtp+l/v9nbFNmCUP1BZMts3G1142MsZfn6eeUKrr4PD1Q==", "dev": true, "dependencies": { @@ -19489,36 +19553,45 @@ }, "engines": { "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, "node_modules/wrap-ansi/node_modules/ansi-regex": { "version": "6.0.1", - "resolved": "https://registry.npmmirror.com/ansi-regex/-/ansi-regex-6.0.1.tgz", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", "dev": true, "engines": { "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" } }, "node_modules/wrap-ansi/node_modules/ansi-styles": { "version": "6.2.1", - "resolved": "https://registry.npmmirror.com/ansi-styles/-/ansi-styles-6.2.1.tgz", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", "dev": true, "engines": { "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, "node_modules/wrap-ansi/node_modules/emoji-regex": { - "version": "10.3.0", - "resolved": "https://registry.npmmirror.com/emoji-regex/-/emoji-regex-10.3.0.tgz", - "integrity": "sha512-QpLs9D9v9kArv4lfDEgg1X/gN5XLnf/A6l9cs8SPZLRZR3ZkY9+kwIQTxm+fsSej5UMYGE8fdoaZVIBlqG0XTw==", + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.4.0.tgz", + "integrity": "sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw==", "dev": true }, "node_modules/wrap-ansi/node_modules/string-width": { - "version": "7.1.0", - "resolved": "https://registry.npmmirror.com/string-width/-/string-width-7.1.0.tgz", - "integrity": "sha512-SEIJCWiX7Kg4c129n48aDRwLbFb2LJmXXFrWBG4NGaRtMQ3myKPKbwrD1BKqQn74oCoNMBVrfDEr5M9YxCsrkw==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", "dev": true, "dependencies": { "emoji-regex": "^10.3.0", @@ -19527,11 +19600,14 @@ }, "engines": { "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/wrap-ansi/node_modules/strip-ansi": { "version": "7.1.0", - "resolved": "https://registry.npmmirror.com/strip-ansi/-/strip-ansi-7.1.0.tgz", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", "dev": true, "dependencies": { @@ -19539,6 +19615,9 @@ }, "engines": { "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" } }, "node_modules/wrappy": { diff --git a/console/src/main/resources/static/console-fe/package.json b/console/src/main/resources/static/console-fe/package.json index 83867a212cf..832d0dd4a75 100644 --- a/console/src/main/resources/static/console-fe/package.json +++ b/console/src/main/resources/static/console-fe/package.json @@ -82,6 +82,7 @@ "axios": "^1.7.4", "browserify-sign": "^4.2.2", "decode-uri-component": "^0.4.1", + "elliptic": "^6.5.7", "history": "^4.10.1", "jquery": "^3.7.1", "loader-utils": "^3.2.1",