This is an automated email from the ASF dual-hosted git repository.
xiaoyu pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/shenyu.git
The following commit(s) were added to refs/heads/master by this push:
new be2c3ff1c [type:fix] fix trie match error (#4515)
be2c3ff1c is described below
commit be2c3ff1ce7cc721c08e54a0c3cdb1b9b89f6381
Author: moremind <[email protected]>
AuthorDate: Fri Mar 31 11:06:37 2023 +0800
[type:fix] fix trie match error (#4515)
* [type:fix] fix trie match error
* [type:fix] fix trie match error
* [type:fix] fix trie match error
* [type:fix] fix trie match error
* [type:fix] fix trie remove error
* [type:fix] fix trie remove error
* [type:fix] fix trie remove error
---------
Co-authored-by: xiaoyu <[email protected]>
---
.../shenyu/admin/service/impl/RuleServiceImpl.java | 23 +++++++++++++--
.../src/main/resources/application.yml | 1 +
.../apache/shenyu/common/config/ShenyuConfig.java | 23 ++++++++++++++-
.../shenyu/plugin/base/AbstractShenyuPlugin.java | 8 +++++
.../base/cache/CommonPluginDataSubscriber.java | 12 +++++---
.../apache/shenyu/plugin/base/trie/ShenyuTrie.java | 34 +++++++++-------------
.../plugin/base/trie/ShenyuTrieRuleListener.java | 6 +++-
.../base/cache/CommonPluginDataSubscriberTest.java | 2 +-
.../web/controller/LocalPluginControllerTest.java | 1 +
9 files changed, 81 insertions(+), 29 deletions(-)
diff --git
a/shenyu-admin/src/main/java/org/apache/shenyu/admin/service/impl/RuleServiceImpl.java
b/shenyu-admin/src/main/java/org/apache/shenyu/admin/service/impl/RuleServiceImpl.java
index 6a01c9a46..27e1c048d 100644
---
a/shenyu-admin/src/main/java/org/apache/shenyu/admin/service/impl/RuleServiceImpl.java
+++
b/shenyu-admin/src/main/java/org/apache/shenyu/admin/service/impl/RuleServiceImpl.java
@@ -54,6 +54,7 @@ import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
@@ -154,8 +155,26 @@ public class RuleServiceImpl implements RuleService {
final int ruleCount = ruleMapper.updateSelective(ruleDO);
// need old data for cleaning
- final List<RuleConditionDO> beforeRuleCondition =
ruleConditionMapper.selectByQuery(new RuleConditionQuery(ruleDO.getId()));
-
+ List<RuleConditionDO> beforeRuleCondition =
ruleConditionMapper.selectByQuery(new RuleConditionQuery(ruleDO.getId()));
+ List<RuleConditionDTO> beforRuleCondition =
beforeRuleCondition.stream().map(ruleConditionDO ->
+ RuleConditionDTO.builder()
+ .ruleId(ruleConditionDO.getRuleId())
+ .operator(ruleConditionDO.getOperator())
+ .paramName(ruleConditionDO.getParamName())
+ .paramType(ruleConditionDO.getParamType())
+ .paramValue(ruleConditionDO.getParamValue())
+ .build()).collect(Collectors.toList());
+ List<RuleConditionDTO> currentRuleCondition =
ruleDTO.getRuleConditions().stream().map(ruleConditionDTO ->
+ RuleConditionDTO.builder()
+ .ruleId(ruleConditionDTO.getRuleId())
+ .operator(ruleConditionDTO.getOperator())
+ .paramName(ruleConditionDTO.getParamName())
+ .paramType(ruleConditionDTO.getParamType())
+ .paramValue(ruleConditionDTO.getParamValue())
+ .build()).collect(Collectors.toList());
+ if (CollectionUtils.isEqualCollection(beforRuleCondition,
currentRuleCondition)) {
+ beforeRuleCondition = Collections.emptyList();
+ }
//delete rule condition then add
ruleConditionMapper.deleteByQuery(new
RuleConditionQuery(ruleDO.getId()));
diff --git a/shenyu-bootstrap/src/main/resources/application.yml
b/shenyu-bootstrap/src/main/resources/application.yml
index b120d8430..d667e4c10 100644
--- a/shenyu-bootstrap/src/main/resources/application.yml
+++ b/shenyu-bootstrap/src/main/resources/application.yml
@@ -75,6 +75,7 @@ shenyu:
initialCapacity: 10000 # initial capacity in cache
maximumSize: 10000 # max size in cache
trie:
+ enabled: true
childrenSize: 10000
pathVariableSize: 1000
pathRuleCacheSize: 1000
diff --git
a/shenyu-common/src/main/java/org/apache/shenyu/common/config/ShenyuConfig.java
b/shenyu-common/src/main/java/org/apache/shenyu/common/config/ShenyuConfig.java
index 42401f124..1bce57657 100644
---
a/shenyu-common/src/main/java/org/apache/shenyu/common/config/ShenyuConfig.java
+++
b/shenyu-common/src/main/java/org/apache/shenyu/common/config/ShenyuConfig.java
@@ -1827,6 +1827,9 @@ public class ShenyuConfig {
* shenyu trie config.
*/
public static class ShenyuTrieConfig {
+
+ private Boolean enabled = Boolean.TRUE;
+
private Long childrenSize = 10000L;
private Long pathRuleCacheSize = 1000L;
@@ -1838,7 +1841,25 @@ public class ShenyuConfig {
* @see TrieMatchModeEvent
*/
private String matchMode =
TrieMatchModeEvent.ANT_PATH_MATCH.getMatchMode();
-
+
+ /**
+ * get match enabled.
+ *
+ * @return Boolean
+ */
+ public Boolean getEnabled() {
+ return enabled;
+ }
+
+ /**
+ * set match enabled.
+ *
+ * @param enabled enabled
+ */
+ public void setEnabled(final Boolean enabled) {
+ this.enabled = enabled;
+ }
+
/**
* get trie children size.
*
diff --git
a/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/AbstractShenyuPlugin.java
b/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/AbstractShenyuPlugin.java
index 29ff186dc..7c0d31348 100644
---
a/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/AbstractShenyuPlugin.java
+++
b/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/AbstractShenyuPlugin.java
@@ -60,6 +60,8 @@ public abstract class AbstractShenyuPlugin implements
ShenyuPlugin {
private ShenyuConfig.MatchCache matchCacheConfig;
private ShenyuTrie trie;
+
+ private ShenyuConfig.ShenyuTrieConfig trieConfig;
/**
* this is Template Method child has Implement your own logic.
@@ -167,6 +169,9 @@ public abstract class AbstractShenyuPlugin implements
ShenyuPlugin {
if (Objects.isNull(trie)) {
trie = SpringBeanUtils.getInstance().getBean(ShenyuTrie.class);
}
+ if (Objects.isNull(trieConfig)) {
+ trieConfig =
SpringBeanUtils.getInstance().getBean(ShenyuConfig.class).getTrie();
+ }
}
private void cacheSelectorData(final String path, final SelectorData
selectorData) {
@@ -310,6 +315,9 @@ public abstract class AbstractShenyuPlugin implements
ShenyuPlugin {
}
private RuleData trieMatchRule(final ServerWebExchange exchange, final
SelectorData selectorData, final String path) {
+ if (!trieConfig.getEnabled()) {
+ return null;
+ }
RuleData ruleData = null;
ShenyuTrieNode shenyuTrieNode = trie.match(path, selectorData.getId());
if (Objects.nonNull(shenyuTrieNode)) {
diff --git
a/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/cache/CommonPluginDataSubscriber.java
b/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/cache/CommonPluginDataSubscriber.java
index 5174271bb..49d49060f 100644
---
a/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/cache/CommonPluginDataSubscriber.java
+++
b/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/cache/CommonPluginDataSubscriber.java
@@ -207,11 +207,15 @@ public class CommonPluginDataSubscriber implements
PluginDataSubscriber {
Optional.ofNullable(handlerMap.get(ruleData.getPluginName()))
.ifPresent(handler -> handler.handlerRule(ruleData));
MatchDataCache.getInstance().removeRuleData(ruleData.getPluginName());
- if
(CollectionUtils.isEmpty(ruleData.getBeforeConditionDataList())) {
- eventPublisher.publishEvent(new
RuleTrieEvent(RuleTrieEventEnum.INSERT, ruleData));
+ if (ruleData.getEnabled()) {
+ if
(CollectionUtils.isEmpty(ruleData.getBeforeConditionDataList())) {
+ eventPublisher.publishEvent(new
RuleTrieEvent(RuleTrieEventEnum.INSERT, ruleData));
+ } else {
+ // if rule data has before condition, update trie
+ eventPublisher.publishEvent(new
RuleTrieEvent(RuleTrieEventEnum.UPDATE, ruleData));
+ }
} else {
- // if rule data has before condition, update trie
- eventPublisher.publishEvent(new
RuleTrieEvent(RuleTrieEventEnum.UPDATE, ruleData));
+ eventPublisher.publishEvent(new
RuleTrieEvent(RuleTrieEventEnum.REMOVE, ruleData));
}
}
}
diff --git
a/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/trie/ShenyuTrie.java
b/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/trie/ShenyuTrie.java
index 13e47002a..1d8727449 100644
---
a/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/trie/ShenyuTrie.java
+++
b/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/trie/ShenyuTrie.java
@@ -26,10 +26,12 @@ import org.apache.shenyu.common.dto.RuleData;
import org.apache.shenyu.common.enums.TrieMatchModeEvent;
import java.util.Arrays;
+import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
+import java.util.Optional;
import java.util.stream.Collectors;
public class ShenyuTrie {
@@ -293,13 +295,9 @@ public class ShenyuTrie {
/**
* remove trie node.
- * remove rules: query node of the current path, if the node exists,
- * checks whether the current node is mapped to multiple plug-in rules.
- * if the plug-in rules have only on mapping, remove the node from parent.
- * if current node exists multi mappings, remove the mapping.
*
- * @param paths paths
- * @param ruleData ruleData
+ * @param paths path list
+ * @param ruleData rule data
*/
public void remove(final List<String> paths, final RuleData ruleData) {
if (CollectionUtils.isNotEmpty(paths)) {
@@ -309,15 +307,15 @@ public class ShenyuTrie {
/**
* remove trie node.
- * remove rules: query node of the current path, if the node exists,
- * checks whether the current node is mapped to multiple plug-in rules.
- * if the plug-in rules have only on mapping, remove the node from parent.
- * if current node exists multi mappings, remove the mapping.
+ * <p> query node of the current path, if the node exists and the node
exist the value of pathRuleCache,
+ * delete a rule with the same ruleId from pathRuleCache.</p>
+ * <p> if current rule data list is empty, children and pathVariablesSet
is null,remove concurrent node from parent node.</p>
*
* @param path path
* @param ruleData ruleData
*/
public void remove(final String path, final RuleData ruleData) {
+ Objects.requireNonNull(ruleData.getId(), "rule id cannot be empty");
if (StringUtils.isNotBlank(path)) {
String strippedPath = StringUtils.strip(path, "/");
String[] pathParts = StringUtils.split(strippedPath, "/");
@@ -327,21 +325,17 @@ public class ShenyuTrie {
if (Objects.nonNull(currentNode) &&
Objects.nonNull(currentNode.getPathRuleCache())) {
// check current mapping
List<RuleData> ruleDataList =
getVal(currentNode.getPathRuleCache(), ruleData.getSelectorId());
- if (CollectionUtils.isNotEmpty(ruleDataList) &&
ruleDataList.size() == 1 && Objects.isNull(currentNode.getChildren())) {
+ ruleDataList =
Optional.ofNullable(ruleDataList).orElse(Collections.emptyList());
+ synchronized (ruleData.getSelectorId()) {
+ ruleDataList.removeIf(rule ->
ruleData.getId().equals(rule.getId()));
+ }
+ if (CollectionUtils.isEmpty(ruleDataList) &&
Objects.isNull(currentNode.getChildren())
+ && Objects.isNull(currentNode.getPathVariablesSet())) {
// remove current node from parent node
String[] parentPathArray = Arrays.copyOfRange(pathParts,
0, pathParts.length - 1);
String parentPath = String.join("/", parentPathArray);
ShenyuTrieNode parentNode = this.getNode(parentPath);
parentNode.getChildren().remove(key);
- } else {
- // remove plugin mapping
- List<RuleData> delRuleData =
getVal(currentNode.getPathRuleCache(), ruleData.getSelectorId());
- if (CollectionUtils.isNotEmpty(delRuleData)) {
- synchronized (ruleData.getSelectorId()) {
- delRuleData.removeIf(rule ->
rule.getId().equals(ruleData.getSelectorId()));
-
currentNode.getPathRuleCache().put(ruleData.getSelectorId(), delRuleData);
- }
- }
}
}
}
diff --git
a/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/trie/ShenyuTrieRuleListener.java
b/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/trie/ShenyuTrieRuleListener.java
index 1925ba216..c78adc1e3 100644
---
a/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/trie/ShenyuTrieRuleListener.java
+++
b/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/trie/ShenyuTrieRuleListener.java
@@ -51,7 +51,11 @@ public class ShenyuTrieRuleListener implements
ApplicationListener<RuleTrieEvent
final ShenyuTrie shenyuTrie =
SpringBeanUtils.getInstance().getBean(ShenyuTrie.class);
switch (eventEnum) {
case INSERT:
- shenyuTrie.putNode(uriPaths, ruleData, ruleData.getId());
+ synchronized (ruleData.getId()) {
+ // insert rule data must remove original rule, and the
operation must atomic
+ shenyuTrie.remove(uriPaths, ruleData);
+ shenyuTrie.putNode(uriPaths, ruleData,
ruleData.getId());
+ }
break;
case UPDATE:
final List<ConditionData> beforeConditionDataList =
ruleData.getBeforeConditionDataList();
diff --git
a/shenyu-plugin/shenyu-plugin-base/src/test/java/org/apache/shenyu/plugin/base/cache/CommonPluginDataSubscriberTest.java
b/shenyu-plugin/shenyu-plugin-base/src/test/java/org/apache/shenyu/plugin/base/cache/CommonPluginDataSubscriberTest.java
index 62b6163c0..986966358 100644
---
a/shenyu-plugin/shenyu-plugin-base/src/test/java/org/apache/shenyu/plugin/base/cache/CommonPluginDataSubscriberTest.java
+++
b/shenyu-plugin/shenyu-plugin-base/src/test/java/org/apache/shenyu/plugin/base/cache/CommonPluginDataSubscriberTest.java
@@ -184,7 +184,7 @@ public final class CommonPluginDataSubscriberTest {
public void testOnRuleSubscribe() {
baseDataCache.cleanRuleData();
- RuleData ruleData =
RuleData.builder().id("1").selectorId(mockSelectorId1).pluginName(mockPluginName1).sort(1).build();
+ RuleData ruleData =
RuleData.builder().id("1").selectorId(mockSelectorId1).enabled(true).pluginName(mockPluginName1).sort(1).build();
commonPluginDataSubscriber.onRuleSubscribe(ruleData);
assertNotNull(baseDataCache.obtainRuleData(ruleData.getSelectorId()));
assertEquals(Lists.newArrayList(ruleData),
baseDataCache.obtainRuleData(ruleData.getSelectorId()));
diff --git
a/shenyu-web/src/test/java/org/apache/shenyu/web/controller/LocalPluginControllerTest.java
b/shenyu-web/src/test/java/org/apache/shenyu/web/controller/LocalPluginControllerTest.java
index fbddc5c14..3c5cbc01a 100644
---
a/shenyu-web/src/test/java/org/apache/shenyu/web/controller/LocalPluginControllerTest.java
+++
b/shenyu-web/src/test/java/org/apache/shenyu/web/controller/LocalPluginControllerTest.java
@@ -426,6 +426,7 @@ public final class LocalPluginControllerTest {
.selectorId(testSelectorId)
.pluginName("testPluginName")
.id(testId)
+ .enabled(true)
.build();
}