- Add a ParameterMetricStorage specific for caching ParameterMetric (moved from ParamSlot) - Add rule map building helper method in ParamFlowRuleUtil so that we can reuse it in other rule managers Signed-off-by: Eric Zhao <sczyh16@gmail.com>master
@@ -43,9 +43,9 @@ import com.alibaba.csp.sentinel.util.TimeUtil; | |||||
* @author Eric Zhao | * @author Eric Zhao | ||||
* @since 0.2.0 | * @since 0.2.0 | ||||
*/ | */ | ||||
final class ParamFlowChecker { | |||||
public final class ParamFlowChecker { | |||||
static boolean passCheck(ResourceWrapper resourceWrapper, /*@Valid*/ ParamFlowRule rule, /*@Valid*/ int count, | |||||
public static boolean passCheck(ResourceWrapper resourceWrapper, /*@Valid*/ ParamFlowRule rule, /*@Valid*/ int count, | |||||
Object... args) { | Object... args) { | ||||
if (args == null) { | if (args == null) { | ||||
return true; | return true; | ||||
@@ -249,7 +249,7 @@ final class ParamFlowChecker { | |||||
private static ParameterMetric getParameterMetric(ResourceWrapper resourceWrapper) { | private static ParameterMetric getParameterMetric(ResourceWrapper resourceWrapper) { | ||||
// Should not be null. | // Should not be null. | ||||
return ParamFlowSlot.getParamMetric(resourceWrapper); | |||||
return ParameterMetricStorage.getParamMetric(resourceWrapper); | |||||
} | } | ||||
@SuppressWarnings("unchecked") | @SuppressWarnings("unchecked") | ||||
@@ -16,7 +16,6 @@ | |||||
package com.alibaba.csp.sentinel.slots.block.flow.param; | package com.alibaba.csp.sentinel.slots.block.flow.param; | ||||
import java.util.ArrayList; | import java.util.ArrayList; | ||||
import java.util.HashSet; | |||||
import java.util.List; | import java.util.List; | ||||
import java.util.Map; | import java.util.Map; | ||||
import java.util.Set; | import java.util.Set; | ||||
@@ -26,9 +25,7 @@ import com.alibaba.csp.sentinel.log.RecordLog; | |||||
import com.alibaba.csp.sentinel.property.DynamicSentinelProperty; | import com.alibaba.csp.sentinel.property.DynamicSentinelProperty; | ||||
import com.alibaba.csp.sentinel.property.PropertyListener; | import com.alibaba.csp.sentinel.property.PropertyListener; | ||||
import com.alibaba.csp.sentinel.property.SentinelProperty; | import com.alibaba.csp.sentinel.property.SentinelProperty; | ||||
import com.alibaba.csp.sentinel.slots.block.RuleConstant; | |||||
import com.alibaba.csp.sentinel.util.AssertUtil; | import com.alibaba.csp.sentinel.util.AssertUtil; | ||||
import com.alibaba.csp.sentinel.util.StringUtil; | |||||
/** | /** | ||||
* Manager for frequent ("hot-spot") parameter flow rules. | * Manager for frequent ("hot-spot") parameter flow rules. | ||||
@@ -39,7 +36,7 @@ import com.alibaba.csp.sentinel.util.StringUtil; | |||||
*/ | */ | ||||
public final class ParamFlowRuleManager { | public final class ParamFlowRuleManager { | ||||
private static final Map<String, Set<ParamFlowRule>> paramFlowRules = new ConcurrentHashMap<>(); | |||||
private static final Map<String, List<ParamFlowRule>> paramFlowRules = new ConcurrentHashMap<>(); | |||||
private final static RulePropertyListener PROPERTY_LISTENER = new RulePropertyListener(); | private final static RulePropertyListener PROPERTY_LISTENER = new RulePropertyListener(); | ||||
private static SentinelProperty<List<ParamFlowRule>> currentProperty = new DynamicSentinelProperty<>(); | private static SentinelProperty<List<ParamFlowRule>> currentProperty = new DynamicSentinelProperty<>(); | ||||
@@ -83,7 +80,7 @@ public final class ParamFlowRuleManager { | |||||
} | } | ||||
public static boolean hasRules(String resourceName) { | public static boolean hasRules(String resourceName) { | ||||
Set<ParamFlowRule> rules = paramFlowRules.get(resourceName); | |||||
List<ParamFlowRule> rules = paramFlowRules.get(resourceName); | |||||
return rules != null && !rules.isEmpty(); | return rules != null && !rules.isEmpty(); | ||||
} | } | ||||
@@ -94,7 +91,7 @@ public final class ParamFlowRuleManager { | |||||
*/ | */ | ||||
public static List<ParamFlowRule> getRules() { | public static List<ParamFlowRule> getRules() { | ||||
List<ParamFlowRule> rules = new ArrayList<>(); | List<ParamFlowRule> rules = new ArrayList<>(); | ||||
for (Map.Entry<String, Set<ParamFlowRule>> entry : paramFlowRules.entrySet()) { | |||||
for (Map.Entry<String, List<ParamFlowRule>> entry : paramFlowRules.entrySet()) { | |||||
rules.addAll(entry.getValue()); | rules.addAll(entry.getValue()); | ||||
} | } | ||||
return rules; | return rules; | ||||
@@ -104,61 +101,38 @@ public final class ParamFlowRuleManager { | |||||
@Override | @Override | ||||
public void configUpdate(List<ParamFlowRule> list) { | public void configUpdate(List<ParamFlowRule> list) { | ||||
Map<String, Set<ParamFlowRule>> rules = aggregateHotParamRules(list); | |||||
Map<String, List<ParamFlowRule>> rules = aggregateAndPrepareParamRules(list); | |||||
if (rules != null) { | if (rules != null) { | ||||
paramFlowRules.clear(); | paramFlowRules.clear(); | ||||
paramFlowRules.putAll(rules); | paramFlowRules.putAll(rules); | ||||
} | } | ||||
RecordLog.info("[ParamFlowRuleManager] Hot spot parameter flow rules received: " + paramFlowRules); | |||||
RecordLog.info("[ParamFlowRuleManager] Parameter flow rules received: " + paramFlowRules); | |||||
} | } | ||||
@Override | @Override | ||||
public void configLoad(List<ParamFlowRule> list) { | public void configLoad(List<ParamFlowRule> list) { | ||||
Map<String, Set<ParamFlowRule>> rules = aggregateHotParamRules(list); | |||||
Map<String, List<ParamFlowRule>> rules = aggregateAndPrepareParamRules(list); | |||||
if (rules != null) { | if (rules != null) { | ||||
paramFlowRules.clear(); | paramFlowRules.clear(); | ||||
paramFlowRules.putAll(rules); | paramFlowRules.putAll(rules); | ||||
} | } | ||||
RecordLog.info("[ParamFlowRuleManager] Hot spot parameter flow rules received: " + paramFlowRules); | |||||
RecordLog.info("[ParamFlowRuleManager] Parameter flow rules received: " + paramFlowRules); | |||||
} | } | ||||
private Map<String, Set<ParamFlowRule>> aggregateHotParamRules(List<ParamFlowRule> list) { | |||||
Map<String, Set<ParamFlowRule>> newRuleMap = new ConcurrentHashMap<>(); | |||||
if (list == null || list.isEmpty()) { | |||||
private Map<String, List<ParamFlowRule>> aggregateAndPrepareParamRules(List<ParamFlowRule> list) { | |||||
Map<String, List<ParamFlowRule>> newRuleMap = ParamFlowRuleUtil.buildParamRuleMap(list); | |||||
if (newRuleMap == null || newRuleMap.isEmpty()) { | |||||
// No parameter flow rules, so clear all the metrics. | // No parameter flow rules, so clear all the metrics. | ||||
ParamFlowSlot.getMetricsMap().clear(); | |||||
ParameterMetricStorage.getMetricsMap().clear(); | |||||
RecordLog.info("[ParamFlowRuleManager] No parameter flow rules, clearing all parameter metrics"); | RecordLog.info("[ParamFlowRuleManager] No parameter flow rules, clearing all parameter metrics"); | ||||
return newRuleMap; | return newRuleMap; | ||||
} | } | ||||
for (ParamFlowRule rule : list) { | |||||
if (!ParamFlowRuleUtil.isValidRule(rule)) { | |||||
RecordLog.warn("[ParamFlowRuleManager] Ignoring invalid rule when loading new rules: " + rule); | |||||
continue; | |||||
} | |||||
if (StringUtil.isBlank(rule.getLimitApp())) { | |||||
rule.setLimitApp(RuleConstant.LIMIT_APP_DEFAULT); | |||||
} | |||||
ParamFlowRuleUtil.fillExceptionFlowItems(rule); | |||||
String resourceName = rule.getResource(); | |||||
Set<ParamFlowRule> ruleSet = newRuleMap.get(resourceName); | |||||
if (ruleSet == null) { | |||||
ruleSet = new HashSet<>(); | |||||
newRuleMap.put(resourceName, ruleSet); | |||||
} | |||||
ruleSet.add(rule); | |||||
} | |||||
// Clear unused hot param metrics. | |||||
// Clear unused parameter metrics. | |||||
Set<String> previousResources = paramFlowRules.keySet(); | Set<String> previousResources = paramFlowRules.keySet(); | ||||
for (String resource : previousResources) { | for (String resource : previousResources) { | ||||
if (!newRuleMap.containsKey(resource)) { | if (!newRuleMap.containsKey(resource)) { | ||||
ParamFlowSlot.clearHotParamMetricForName(resource); | |||||
ParameterMetricStorage.clearParamMetricForResource(resource); | |||||
} | } | ||||
} | } | ||||
@@ -166,6 +140,5 @@ public final class ParamFlowRuleManager { | |||||
} | } | ||||
} | } | ||||
private ParamFlowRuleManager() { | |||||
} | |||||
private ParamFlowRuleManager() {} | |||||
} | } |
@@ -17,18 +17,32 @@ package com.alibaba.csp.sentinel.slots.block.flow.param; | |||||
import java.util.ArrayList; | import java.util.ArrayList; | ||||
import java.util.HashMap; | import java.util.HashMap; | ||||
import java.util.HashSet; | |||||
import java.util.List; | import java.util.List; | ||||
import java.util.Map; | import java.util.Map; | ||||
import java.util.Map.Entry; | |||||
import java.util.Set; | |||||
import java.util.concurrent.ConcurrentHashMap; | |||||
import com.alibaba.csp.sentinel.log.RecordLog; | import com.alibaba.csp.sentinel.log.RecordLog; | ||||
import com.alibaba.csp.sentinel.slots.block.RuleConstant; | |||||
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleUtil; | import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleUtil; | ||||
import com.alibaba.csp.sentinel.util.AssertUtil; | |||||
import com.alibaba.csp.sentinel.util.StringUtil; | import com.alibaba.csp.sentinel.util.StringUtil; | ||||
import com.alibaba.csp.sentinel.util.function.Function; | |||||
import com.alibaba.csp.sentinel.util.function.Predicate; | |||||
/** | /** | ||||
* @author Eric Zhao | * @author Eric Zhao | ||||
*/ | */ | ||||
public final class ParamFlowRuleUtil { | public final class ParamFlowRuleUtil { | ||||
/** | |||||
* Check whether the provided rule is valid. | |||||
* | |||||
* @param rule any parameter rule | |||||
* @return true if valid, otherwise false | |||||
*/ | |||||
public static boolean isValidRule(ParamFlowRule rule) { | public static boolean isValidRule(ParamFlowRule rule) { | ||||
return rule != null && !StringUtil.isBlank(rule.getResource()) && rule.getCount() >= 0 | return rule != null && !StringUtil.isBlank(rule.getResource()) && rule.getCount() >= 0 | ||||
&& rule.getGrade() >= 0 && rule.getParamIdx() != null | && rule.getGrade() >= 0 && rule.getParamIdx() != null | ||||
@@ -55,6 +69,11 @@ public final class ParamFlowRuleUtil { | |||||
return id != null && id > 0; | return id != null && id > 0; | ||||
} | } | ||||
/** | |||||
* Fill the parameter rule with parsed items. | |||||
* | |||||
* @param rule valid parameter rule | |||||
*/ | |||||
public static void fillExceptionFlowItems(ParamFlowRule rule) { | public static void fillExceptionFlowItems(ParamFlowRule rule) { | ||||
if (rule != null) { | if (rule != null) { | ||||
if (rule.getParamFlowItemList() == null) { | if (rule.getParamFlowItemList() == null) { | ||||
@@ -66,11 +85,111 @@ public final class ParamFlowRuleUtil { | |||||
} | } | ||||
} | } | ||||
/** | |||||
* Build the flow rule map from raw list of flow rules, grouping by resource name. | |||||
* | |||||
* @param list raw list of flow rules | |||||
* @return constructed new flow rule map; empty map if list is null or empty, or no valid rules | |||||
* @since 1.6.1 | |||||
*/ | |||||
public static Map<String, List<ParamFlowRule>> buildParamRuleMap(List<ParamFlowRule> list) { | |||||
return buildParamRuleMap(list, null); | |||||
} | |||||
/** | |||||
* Build the parameter flow rule map from raw list of rules, grouping by resource name. | |||||
* | |||||
* @param list raw list of parameter flow rules | |||||
* @param filter rule filter | |||||
* @return constructed new parameter flow rule map; empty map if list is null or empty, or no wanted rules | |||||
* @since 1.6.1 | |||||
*/ | |||||
public static Map<String, List<ParamFlowRule>> buildParamRuleMap(List<ParamFlowRule> list, | |||||
Predicate<ParamFlowRule> filter) { | |||||
return buildParamRuleMap(list, filter, true); | |||||
} | |||||
/** | |||||
* Build the parameter flow rule map from raw list of rules, grouping by resource name. | |||||
* | |||||
* @param list raw list of parameter flow rules | |||||
* @param filter rule filter | |||||
* @param shouldSort whether the rules should be sorted | |||||
* @return constructed new parameter flow rule map; empty map if list is null or empty, or no wanted rules | |||||
* @since 1.6.1 | |||||
*/ | |||||
public static Map<String, List<ParamFlowRule>> buildParamRuleMap(List<ParamFlowRule> list, | |||||
Predicate<ParamFlowRule> filter, | |||||
boolean shouldSort) { | |||||
return buildParamRuleMap(list, EXTRACT_RESOURCE, filter, shouldSort); | |||||
} | |||||
/** | |||||
* Build the rule map from raw list of parameter flow rules, grouping by provided group function. | |||||
* | |||||
* @param list raw list of parameter flow rules | |||||
* @param groupFunction grouping function of the map (by key) | |||||
* @param filter rule filter | |||||
* @param shouldSort whether the rules should be sorted | |||||
* @param <K> type of key | |||||
* @return constructed new rule map; empty map if list is null or empty, or no wanted rules | |||||
* @since 1.6.1 | |||||
*/ | |||||
public static <K> Map<K, List<ParamFlowRule>> buildParamRuleMap(List<ParamFlowRule> list, | |||||
Function<ParamFlowRule, K> groupFunction, | |||||
Predicate<ParamFlowRule> filter, | |||||
boolean shouldSort) { | |||||
AssertUtil.notNull(groupFunction, "groupFunction should not be null"); | |||||
Map<K, List<ParamFlowRule>> newRuleMap = new ConcurrentHashMap<>(); | |||||
if (list == null || list.isEmpty()) { | |||||
return newRuleMap; | |||||
} | |||||
Map<K, Set<ParamFlowRule>> tmpMap = new ConcurrentHashMap<>(); | |||||
for (ParamFlowRule rule : list) { | |||||
if (!ParamFlowRuleUtil.isValidRule(rule)) { | |||||
RecordLog.warn("[ParamFlowRuleManager] Ignoring invalid rule when loading new rules: " + rule); | |||||
continue; | |||||
} | |||||
if (filter != null && !filter.test(rule)) { | |||||
continue; | |||||
} | |||||
if (StringUtil.isBlank(rule.getLimitApp())) { | |||||
rule.setLimitApp(RuleConstant.LIMIT_APP_DEFAULT); | |||||
} | |||||
ParamFlowRuleUtil.fillExceptionFlowItems(rule); | |||||
K key = groupFunction.apply(rule); | |||||
if (key == null) { | |||||
continue; | |||||
} | |||||
Set<ParamFlowRule> flowRules = tmpMap.get(key); | |||||
if (flowRules == null) { | |||||
// Use hash set here to remove duplicate rules. | |||||
flowRules = new HashSet<>(); | |||||
tmpMap.put(key, flowRules); | |||||
} | |||||
flowRules.add(rule); | |||||
} | |||||
for (Entry<K, Set<ParamFlowRule>> entries : tmpMap.entrySet()) { | |||||
List<ParamFlowRule> rules = new ArrayList<>(entries.getValue()); | |||||
if (shouldSort) { | |||||
// TODO: Sort the rules. | |||||
} | |||||
newRuleMap.put(entries.getKey(), rules); | |||||
} | |||||
return newRuleMap; | |||||
} | |||||
static Map<Object, Integer> parseHotItems(List<ParamFlowItem> items) { | static Map<Object, Integer> parseHotItems(List<ParamFlowItem> items) { | ||||
Map<Object, Integer> itemMap = new HashMap<Object, Integer>(); | |||||
if (items == null || items.isEmpty()) { | if (items == null || items.isEmpty()) { | ||||
return itemMap; | |||||
return new HashMap<>(); | |||||
} | } | ||||
Map<Object, Integer> itemMap = new HashMap<>(items.size()); | |||||
for (ParamFlowItem item : items) { | for (ParamFlowItem item : items) { | ||||
// Value should not be null. | // Value should not be null. | ||||
Object value; | Object value; | ||||
@@ -120,5 +239,12 @@ public final class ParamFlowRuleUtil { | |||||
return value; | return value; | ||||
} | } | ||||
private static final Function<ParamFlowRule, String> EXTRACT_RESOURCE = new Function<ParamFlowRule, String>() { | |||||
@Override | |||||
public String apply(ParamFlowRule rule) { | |||||
return rule.getResource(); | |||||
} | |||||
}; | |||||
private ParamFlowRuleUtil() {} | private ParamFlowRuleUtil() {} | ||||
} | } |
@@ -16,18 +16,12 @@ | |||||
package com.alibaba.csp.sentinel.slots.block.flow.param; | package com.alibaba.csp.sentinel.slots.block.flow.param; | ||||
import java.util.List; | import java.util.List; | ||||
import java.util.Map; | |||||
import java.util.concurrent.ConcurrentHashMap; | |||||
import com.alibaba.csp.sentinel.EntryType; | |||||
import com.alibaba.csp.sentinel.context.Context; | import com.alibaba.csp.sentinel.context.Context; | ||||
import com.alibaba.csp.sentinel.log.RecordLog; | |||||
import com.alibaba.csp.sentinel.node.DefaultNode; | import com.alibaba.csp.sentinel.node.DefaultNode; | ||||
import com.alibaba.csp.sentinel.slotchain.AbstractLinkedProcessorSlot; | import com.alibaba.csp.sentinel.slotchain.AbstractLinkedProcessorSlot; | ||||
import com.alibaba.csp.sentinel.slotchain.ResourceWrapper; | import com.alibaba.csp.sentinel.slotchain.ResourceWrapper; | ||||
import com.alibaba.csp.sentinel.slotchain.StringResourceWrapper; | |||||
import com.alibaba.csp.sentinel.slots.block.BlockException; | import com.alibaba.csp.sentinel.slots.block.BlockException; | ||||
import com.alibaba.csp.sentinel.util.StringUtil; | |||||
/** | /** | ||||
* A processor slot that is responsible for flow control by frequent ("hot spot") parameters. | * A processor slot that is responsible for flow control by frequent ("hot spot") parameters. | ||||
@@ -38,13 +32,6 @@ import com.alibaba.csp.sentinel.util.StringUtil; | |||||
*/ | */ | ||||
public class ParamFlowSlot extends AbstractLinkedProcessorSlot<DefaultNode> { | public class ParamFlowSlot extends AbstractLinkedProcessorSlot<DefaultNode> { | ||||
private static final Map<ResourceWrapper, ParameterMetric> metricsMap = new ConcurrentHashMap<>(); | |||||
/** | |||||
* Lock for a specific resource. | |||||
*/ | |||||
private final Object LOCK = new Object(); | |||||
@Override | @Override | ||||
public void entry(Context context, ResourceWrapper resourceWrapper, DefaultNode node, int count, | public void entry(Context context, ResourceWrapper resourceWrapper, DefaultNode node, int count, | ||||
boolean prioritized, Object... args) throws Throwable { | boolean prioritized, Object... args) throws Throwable { | ||||
@@ -68,7 +55,7 @@ public class ParamFlowSlot extends AbstractLinkedProcessorSlot<DefaultNode> { | |||||
if (-paramIdx <= length) { | if (-paramIdx <= length) { | ||||
rule.setParamIdx(length + paramIdx); | rule.setParamIdx(length + paramIdx); | ||||
} else { | } else { | ||||
// illegal index, give it a illegal positive value, latter rule check will pass | |||||
// Illegal index, give it a illegal positive value, latter rule checking will pass. | |||||
rule.setParamIdx(-paramIdx); | rule.setParamIdx(-paramIdx); | ||||
} | } | ||||
} | } | ||||
@@ -87,7 +74,7 @@ public class ParamFlowSlot extends AbstractLinkedProcessorSlot<DefaultNode> { | |||||
applyRealParamIdx(rule, args.length); | applyRealParamIdx(rule, args.length); | ||||
// Initialize the parameter metrics. | // Initialize the parameter metrics. | ||||
initHotParamMetricsFor(resourceWrapper, rule); | |||||
ParameterMetricStorage.initParamMetricsFor(resourceWrapper, rule); | |||||
if (!ParamFlowChecker.passCheck(resourceWrapper, rule, count, args)) { | if (!ParamFlowChecker.passCheck(resourceWrapper, rule, count, args)) { | ||||
String triggeredParam = ""; | String triggeredParam = ""; | ||||
@@ -99,60 +86,4 @@ public class ParamFlowSlot extends AbstractLinkedProcessorSlot<DefaultNode> { | |||||
} | } | ||||
} | } | ||||
} | } | ||||
/** | |||||
* Init the parameter metric and index map for given resource. | |||||
* Package-private for test. | |||||
* | |||||
* @param resourceWrapper resource to init | |||||
* @param rule relevant rule | |||||
*/ | |||||
void initHotParamMetricsFor(ResourceWrapper resourceWrapper, /*@Valid*/ ParamFlowRule rule) { | |||||
ParameterMetric metric; | |||||
// Assume that the resource is valid. | |||||
if ((metric = metricsMap.get(resourceWrapper)) == null) { | |||||
synchronized (LOCK) { | |||||
if ((metric = metricsMap.get(resourceWrapper)) == null) { | |||||
metric = new ParameterMetric(); | |||||
metricsMap.put(resourceWrapper, metric); | |||||
RecordLog.info("[ParamFlowSlot] Creating parameter metric for: " + resourceWrapper.getName()); | |||||
} | |||||
} | |||||
} | |||||
metric.initialize(rule); | |||||
} | |||||
public static ParameterMetric getParamMetric(ResourceWrapper resourceWrapper) { | |||||
if (resourceWrapper == null || resourceWrapper.getName() == null) { | |||||
return null; | |||||
} | |||||
return metricsMap.get(resourceWrapper); | |||||
} | |||||
public static ParameterMetric getHotParamMetricForName(String resourceName) { | |||||
if (StringUtil.isBlank(resourceName)) { | |||||
return null; | |||||
} | |||||
for (EntryType nodeType : EntryType.values()) { | |||||
ParameterMetric metric = metricsMap.get(new StringResourceWrapper(resourceName, nodeType)); | |||||
if (metric != null) { | |||||
return metric; | |||||
} | |||||
} | |||||
return null; | |||||
} | |||||
static void clearHotParamMetricForName(String resourceName) { | |||||
if (StringUtil.isBlank(resourceName)) { | |||||
return; | |||||
} | |||||
for (EntryType nodeType : EntryType.values()) { | |||||
metricsMap.remove(new StringResourceWrapper(resourceName, nodeType)); | |||||
} | |||||
RecordLog.info("[ParamFlowSlot] Clearing parameter metric for: " + resourceName); | |||||
} | |||||
static Map<ResourceWrapper, ParameterMetric> getMetricsMap() { | |||||
return metricsMap; | |||||
} | |||||
} | } |
@@ -0,0 +1,91 @@ | |||||
/* | |||||
* Copyright 1999-2019 Alibaba Group Holding Ltd. | |||||
* | |||||
* Licensed 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 | |||||
* | |||||
* https://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 com.alibaba.csp.sentinel.slots.block.flow.param; | |||||
import java.util.Map; | |||||
import java.util.concurrent.ConcurrentHashMap; | |||||
import com.alibaba.csp.sentinel.log.RecordLog; | |||||
import com.alibaba.csp.sentinel.slotchain.ResourceWrapper; | |||||
import com.alibaba.csp.sentinel.util.StringUtil; | |||||
/** | |||||
* @author Eric Zhao | |||||
* @since 1.6.1 | |||||
*/ | |||||
public final class ParameterMetricStorage { | |||||
private static final Map<String, ParameterMetric> metricsMap = new ConcurrentHashMap<>(); | |||||
/** | |||||
* Lock for a specific resource. | |||||
*/ | |||||
private static final Object LOCK = new Object(); | |||||
/** | |||||
* Init the parameter metric and index map for given resource. | |||||
* Package-private for test. | |||||
* | |||||
* @param resourceWrapper resource to init | |||||
* @param rule relevant rule | |||||
*/ | |||||
public static void initParamMetricsFor(ResourceWrapper resourceWrapper, /*@Valid*/ ParamFlowRule rule) { | |||||
if (resourceWrapper == null || resourceWrapper.getName() == null) { | |||||
return; | |||||
} | |||||
String resourceName = resourceWrapper.getName(); | |||||
ParameterMetric metric; | |||||
// Assume that the resource is valid. | |||||
if ((metric = metricsMap.get(resourceName)) == null) { | |||||
synchronized (LOCK) { | |||||
if ((metric = metricsMap.get(resourceName)) == null) { | |||||
metric = new ParameterMetric(); | |||||
metricsMap.put(resourceWrapper.getName(), metric); | |||||
RecordLog.info("[ParameterMetricStorage] Creating parameter metric for: " + resourceWrapper.getName()); | |||||
} | |||||
} | |||||
} | |||||
metric.initialize(rule); | |||||
} | |||||
public static ParameterMetric getParamMetric(ResourceWrapper resourceWrapper) { | |||||
if (resourceWrapper == null || resourceWrapper.getName() == null) { | |||||
return null; | |||||
} | |||||
return metricsMap.get(resourceWrapper.getName()); | |||||
} | |||||
public static ParameterMetric getParamMetricForResource(String resourceName) { | |||||
if (resourceName == null) { | |||||
return null; | |||||
} | |||||
return metricsMap.get(resourceName); | |||||
} | |||||
public static void clearParamMetricForResource(String resourceName) { | |||||
if (StringUtil.isBlank(resourceName)) { | |||||
return; | |||||
} | |||||
metricsMap.remove(resourceName); | |||||
RecordLog.info("[ParameterMetricStorage] Clearing parameter metric for: " + resourceName); | |||||
} | |||||
static Map<String, ParameterMetric> getMetricsMap() { | |||||
return metricsMap; | |||||
} | |||||
private ParameterMetricStorage() {} | |||||
} |
@@ -20,8 +20,8 @@ import com.alibaba.csp.sentinel.node.DefaultNode; | |||||
import com.alibaba.csp.sentinel.slotchain.ProcessorSlotEntryCallback; | import com.alibaba.csp.sentinel.slotchain.ProcessorSlotEntryCallback; | ||||
import com.alibaba.csp.sentinel.slotchain.ResourceWrapper; | import com.alibaba.csp.sentinel.slotchain.ResourceWrapper; | ||||
import com.alibaba.csp.sentinel.slots.block.BlockException; | import com.alibaba.csp.sentinel.slots.block.BlockException; | ||||
import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowSlot; | |||||
import com.alibaba.csp.sentinel.slots.block.flow.param.ParameterMetric; | import com.alibaba.csp.sentinel.slots.block.flow.param.ParameterMetric; | ||||
import com.alibaba.csp.sentinel.slots.block.flow.param.ParameterMetricStorage; | |||||
/** | /** | ||||
* @author Eric Zhao | * @author Eric Zhao | ||||
@@ -32,7 +32,7 @@ public class ParamFlowStatisticEntryCallback implements ProcessorSlotEntryCallba | |||||
@Override | @Override | ||||
public void onPass(Context context, ResourceWrapper resourceWrapper, DefaultNode node, int count, Object... args) { | public void onPass(Context context, ResourceWrapper resourceWrapper, DefaultNode node, int count, Object... args) { | ||||
// The "hot spot" parameter metric is present only if parameter flow rules for the resource exist. | // The "hot spot" parameter metric is present only if parameter flow rules for the resource exist. | ||||
ParameterMetric parameterMetric = ParamFlowSlot.getParamMetric(resourceWrapper); | |||||
ParameterMetric parameterMetric = ParameterMetricStorage.getParamMetric(resourceWrapper); | |||||
if (parameterMetric != null) { | if (parameterMetric != null) { | ||||
parameterMetric.addThreadCount(args); | parameterMetric.addThreadCount(args); | ||||
@@ -18,8 +18,8 @@ package com.alibaba.csp.sentinel.slots.statistic; | |||||
import com.alibaba.csp.sentinel.context.Context; | import com.alibaba.csp.sentinel.context.Context; | ||||
import com.alibaba.csp.sentinel.slotchain.ProcessorSlotExitCallback; | import com.alibaba.csp.sentinel.slotchain.ProcessorSlotExitCallback; | ||||
import com.alibaba.csp.sentinel.slotchain.ResourceWrapper; | import com.alibaba.csp.sentinel.slotchain.ResourceWrapper; | ||||
import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowSlot; | |||||
import com.alibaba.csp.sentinel.slots.block.flow.param.ParameterMetric; | import com.alibaba.csp.sentinel.slots.block.flow.param.ParameterMetric; | ||||
import com.alibaba.csp.sentinel.slots.block.flow.param.ParameterMetricStorage; | |||||
/** | /** | ||||
* @author Eric Zhao | * @author Eric Zhao | ||||
@@ -30,7 +30,7 @@ public class ParamFlowStatisticExitCallback implements ProcessorSlotExitCallback | |||||
@Override | @Override | ||||
public void onExit(Context context, ResourceWrapper resourceWrapper, int count, Object... args) { | public void onExit(Context context, ResourceWrapper resourceWrapper, int count, Object... args) { | ||||
if (context.getCurEntry().getError() == null) { | if (context.getCurEntry().getError() == null) { | ||||
ParameterMetric parameterMetric = ParamFlowSlot.getParamMetric(resourceWrapper); | |||||
ParameterMetric parameterMetric = ParameterMetricStorage.getParamMetric(resourceWrapper); | |||||
if (parameterMetric != null) { | if (parameterMetric != null) { | ||||
parameterMetric.decreaseThreadCount(args); | parameterMetric.decreaseThreadCount(args); | ||||
@@ -90,7 +90,7 @@ public class ParamFlowCheckerTest { | |||||
rule.setParsedHotItems(map); | rule.setParsedHotItems(map); | ||||
ParameterMetric metric = new ParameterMetric(); | ParameterMetric metric = new ParameterMetric(); | ||||
ParamFlowSlot.getMetricsMap().put(resourceWrapper, metric); | |||||
ParameterMetricStorage.getMetricsMap().put(resourceWrapper.getName(), metric); | |||||
metric.getRuleTimeCounterMap().put(rule, new ConcurrentLinkedHashMapWrapper<Object, AtomicLong>(4000)); | metric.getRuleTimeCounterMap().put(rule, new ConcurrentLinkedHashMapWrapper<Object, AtomicLong>(4000)); | ||||
assertTrue(ParamFlowChecker.passSingleValueCheck(resourceWrapper, rule, 1, valueA)); | assertTrue(ParamFlowChecker.passSingleValueCheck(resourceWrapper, rule, 1, valueA)); | ||||
@@ -127,7 +127,7 @@ public class ParamFlowCheckerTest { | |||||
when(metric.getThreadCount(paramIdx, valueB)).thenReturn(globalThreshold - 1); | when(metric.getThreadCount(paramIdx, valueB)).thenReturn(globalThreshold - 1); | ||||
when(metric.getThreadCount(paramIdx, valueC)).thenReturn(globalThreshold - 1); | when(metric.getThreadCount(paramIdx, valueC)).thenReturn(globalThreshold - 1); | ||||
when(metric.getThreadCount(paramIdx, valueD)).thenReturn(globalThreshold + 1); | when(metric.getThreadCount(paramIdx, valueD)).thenReturn(globalThreshold + 1); | ||||
ParamFlowSlot.getMetricsMap().put(resourceWrapper, metric); | |||||
ParameterMetricStorage.getMetricsMap().put(resourceWrapper.getName(), metric); | |||||
assertTrue(ParamFlowChecker.passSingleValueCheck(resourceWrapper, rule, 1, valueA)); | assertTrue(ParamFlowChecker.passSingleValueCheck(resourceWrapper, rule, 1, valueA)); | ||||
assertFalse(ParamFlowChecker.passSingleValueCheck(resourceWrapper, rule, 1, valueB)); | assertFalse(ParamFlowChecker.passSingleValueCheck(resourceWrapper, rule, 1, valueB)); | ||||
@@ -158,7 +158,7 @@ public class ParamFlowCheckerTest { | |||||
String v1 = "a", v2 = "B", v3 = "Cc"; | String v1 = "a", v2 = "B", v3 = "Cc"; | ||||
List<String> list = Arrays.asList(v1, v2, v3); | List<String> list = Arrays.asList(v1, v2, v3); | ||||
ParameterMetric metric = new ParameterMetric(); | ParameterMetric metric = new ParameterMetric(); | ||||
ParamFlowSlot.getMetricsMap().put(resourceWrapper, metric); | |||||
ParameterMetricStorage.getMetricsMap().put(resourceWrapper.getName(), metric); | |||||
metric.getRuleTimeCounterMap().put(rule, new ConcurrentLinkedHashMapWrapper<Object, AtomicLong>(4000)); | metric.getRuleTimeCounterMap().put(rule, new ConcurrentLinkedHashMapWrapper<Object, AtomicLong>(4000)); | ||||
metric.getRuleTokenCounterMap().put(rule, new ConcurrentLinkedHashMapWrapper<Object, AtomicInteger>(4000)); | metric.getRuleTokenCounterMap().put(rule, new ConcurrentLinkedHashMapWrapper<Object, AtomicInteger>(4000)); | ||||
@@ -181,7 +181,7 @@ public class ParamFlowCheckerTest { | |||||
String v1 = "a", v2 = "B", v3 = "Cc"; | String v1 = "a", v2 = "B", v3 = "Cc"; | ||||
Object arr = new String[] {v1, v2, v3}; | Object arr = new String[] {v1, v2, v3}; | ||||
ParameterMetric metric = new ParameterMetric(); | ParameterMetric metric = new ParameterMetric(); | ||||
ParamFlowSlot.getMetricsMap().put(resourceWrapper, metric); | |||||
ParameterMetricStorage.getMetricsMap().put(resourceWrapper.getName(), metric); | |||||
metric.getRuleTimeCounterMap().put(rule, new ConcurrentLinkedHashMapWrapper<Object, AtomicLong>(4000)); | metric.getRuleTimeCounterMap().put(rule, new ConcurrentLinkedHashMapWrapper<Object, AtomicLong>(4000)); | ||||
assertTrue(ParamFlowChecker.passCheck(resourceWrapper, rule, 1, arr)); | assertTrue(ParamFlowChecker.passCheck(resourceWrapper, rule, 1, arr)); | ||||
@@ -190,11 +190,11 @@ public class ParamFlowCheckerTest { | |||||
@Before | @Before | ||||
public void setUp() throws Exception { | public void setUp() throws Exception { | ||||
ParamFlowSlot.getMetricsMap().clear(); | |||||
ParameterMetricStorage.getMetricsMap().clear(); | |||||
} | } | ||||
@After | @After | ||||
public void tearDown() throws Exception { | public void tearDown() throws Exception { | ||||
ParamFlowSlot.getMetricsMap().clear(); | |||||
ParameterMetricStorage.getMetricsMap().clear(); | |||||
} | } | ||||
} | } |
@@ -1,3 +1,18 @@ | |||||
/* | |||||
* Copyright 1999-2019 Alibaba Group Holding Ltd. | |||||
* | |||||
* Licensed 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 | |||||
* | |||||
* https://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 com.alibaba.csp.sentinel.slots.block.flow.param; | package com.alibaba.csp.sentinel.slots.block.flow.param; | ||||
import static org.junit.Assert.assertEquals; | import static org.junit.Assert.assertEquals; | ||||
@@ -41,7 +56,7 @@ public class ParamFlowDefaultCheckerTest extends AbstractTimeBasedTest { | |||||
String valueA = "valueA"; | String valueA = "valueA"; | ||||
ParameterMetric metric = new ParameterMetric(); | ParameterMetric metric = new ParameterMetric(); | ||||
ParamFlowSlot.getMetricsMap().put(resourceWrapper, metric); | |||||
ParameterMetricStorage.getMetricsMap().put(resourceWrapper.getName(), metric); | |||||
metric.getRuleTimeCounterMap().put(rule, new ConcurrentLinkedHashMapWrapper<Object, AtomicLong>(4000)); | metric.getRuleTimeCounterMap().put(rule, new ConcurrentLinkedHashMapWrapper<Object, AtomicLong>(4000)); | ||||
metric.getRuleTokenCounterMap().put(rule, | metric.getRuleTokenCounterMap().put(rule, | ||||
new ConcurrentLinkedHashMapWrapper<Object, AtomicInteger>(4000)); | new ConcurrentLinkedHashMapWrapper<Object, AtomicInteger>(4000)); | ||||
@@ -81,7 +96,7 @@ public class ParamFlowDefaultCheckerTest extends AbstractTimeBasedTest { | |||||
String valueA = "valueA"; | String valueA = "valueA"; | ||||
ParameterMetric metric = new ParameterMetric(); | ParameterMetric metric = new ParameterMetric(); | ||||
ParamFlowSlot.getMetricsMap().put(resourceWrapper, metric); | |||||
ParameterMetricStorage.getMetricsMap().put(resourceWrapper.getName(), metric); | |||||
metric.getRuleTimeCounterMap().put(rule, new ConcurrentLinkedHashMapWrapper<Object, AtomicLong>(4000)); | metric.getRuleTimeCounterMap().put(rule, new ConcurrentLinkedHashMapWrapper<Object, AtomicLong>(4000)); | ||||
metric.getRuleTokenCounterMap().put(rule, | metric.getRuleTokenCounterMap().put(rule, | ||||
new ConcurrentLinkedHashMapWrapper<Object, AtomicInteger>(4000)); | new ConcurrentLinkedHashMapWrapper<Object, AtomicInteger>(4000)); | ||||
@@ -151,7 +166,7 @@ public class ParamFlowDefaultCheckerTest extends AbstractTimeBasedTest { | |||||
String valueA = "helloWorld"; | String valueA = "helloWorld"; | ||||
ParameterMetric metric = new ParameterMetric(); | ParameterMetric metric = new ParameterMetric(); | ||||
ParamFlowSlot.getMetricsMap().put(resourceWrapper, metric); | |||||
ParameterMetricStorage.getMetricsMap().put(resourceWrapper.getName(), metric); | |||||
metric.getRuleTimeCounterMap().put(rule, new ConcurrentLinkedHashMapWrapper<Object, AtomicLong>(4000)); | metric.getRuleTimeCounterMap().put(rule, new ConcurrentLinkedHashMapWrapper<Object, AtomicLong>(4000)); | ||||
metric.getRuleTokenCounterMap().put(rule, | metric.getRuleTokenCounterMap().put(rule, | ||||
new ConcurrentLinkedHashMapWrapper<Object, AtomicInteger>(4000)); | new ConcurrentLinkedHashMapWrapper<Object, AtomicInteger>(4000)); | ||||
@@ -204,7 +219,7 @@ public class ParamFlowDefaultCheckerTest extends AbstractTimeBasedTest { | |||||
final String valueA = "valueA"; | final String valueA = "valueA"; | ||||
ParameterMetric metric = new ParameterMetric(); | ParameterMetric metric = new ParameterMetric(); | ||||
ParamFlowSlot.getMetricsMap().put(resourceWrapper, metric); | |||||
ParameterMetricStorage.getMetricsMap().put(resourceWrapper.getName(), metric); | |||||
metric.getRuleTimeCounterMap().put(rule, new ConcurrentLinkedHashMapWrapper<Object, AtomicLong>(4000)); | metric.getRuleTimeCounterMap().put(rule, new ConcurrentLinkedHashMapWrapper<Object, AtomicLong>(4000)); | ||||
metric.getRuleTokenCounterMap().put(rule, | metric.getRuleTokenCounterMap().put(rule, | ||||
new ConcurrentLinkedHashMapWrapper<Object, AtomicInteger>(4000)); | new ConcurrentLinkedHashMapWrapper<Object, AtomicInteger>(4000)); | ||||
@@ -270,11 +285,11 @@ public class ParamFlowDefaultCheckerTest extends AbstractTimeBasedTest { | |||||
@Before | @Before | ||||
public void setUp() throws Exception { | public void setUp() throws Exception { | ||||
ParamFlowSlot.getMetricsMap().clear(); | |||||
ParameterMetricStorage.getMetricsMap().clear(); | |||||
} | } | ||||
@After | @After | ||||
public void tearDown() throws Exception { | public void tearDown() throws Exception { | ||||
ParamFlowSlot.getMetricsMap().clear(); | |||||
ParameterMetricStorage.getMetricsMap().clear(); | |||||
} | } | ||||
} | } |
@@ -19,8 +19,6 @@ import java.util.Arrays; | |||||
import java.util.Collections; | import java.util.Collections; | ||||
import java.util.List; | import java.util.List; | ||||
import com.alibaba.csp.sentinel.EntryType; | |||||
import com.alibaba.csp.sentinel.slotchain.StringResourceWrapper; | |||||
import com.alibaba.csp.sentinel.slots.block.RuleConstant; | import com.alibaba.csp.sentinel.slots.block.RuleConstant; | ||||
import org.junit.After; | import org.junit.After; | ||||
@@ -40,33 +38,36 @@ public class ParamFlowRuleManagerTest { | |||||
@Before | @Before | ||||
public void setUp() { | public void setUp() { | ||||
ParamFlowRuleManager.loadRules(null); | ParamFlowRuleManager.loadRules(null); | ||||
ParameterMetricStorage.getMetricsMap().clear(); | |||||
} | } | ||||
@After | @After | ||||
public void tearDown() { | public void tearDown() { | ||||
ParamFlowRuleManager.loadRules(null); | ParamFlowRuleManager.loadRules(null); | ||||
ParameterMetricStorage.getMetricsMap().clear(); | |||||
} | } | ||||
@Test | @Test | ||||
public void testLoadHotParamRulesClearingUnusedMetrics() { | |||||
public void testLoadParamRulesClearingUnusedMetrics() { | |||||
final String resA = "resA"; | final String resA = "resA"; | ||||
ParamFlowRule ruleA = new ParamFlowRule(resA) | ParamFlowRule ruleA = new ParamFlowRule(resA) | ||||
.setCount(1) | .setCount(1) | ||||
.setParamIdx(0); | .setParamIdx(0); | ||||
ParamFlowRuleManager.loadRules(Collections.singletonList(ruleA)); | ParamFlowRuleManager.loadRules(Collections.singletonList(ruleA)); | ||||
ParamFlowSlot.getMetricsMap().put(new StringResourceWrapper(resA, EntryType.IN), new ParameterMetric()); | |||||
assertNotNull(ParamFlowSlot.getHotParamMetricForName(resA)); | |||||
ParameterMetricStorage.getMetricsMap().put(resA, new ParameterMetric()); | |||||
assertNotNull(ParameterMetricStorage.getParamMetricForResource(resA)); | |||||
final String resB = "resB"; | final String resB = "resB"; | ||||
ParamFlowRule ruleB = new ParamFlowRule(resB) | ParamFlowRule ruleB = new ParamFlowRule(resB) | ||||
.setCount(2) | .setCount(2) | ||||
.setParamIdx(1); | .setParamIdx(1); | ||||
ParamFlowRuleManager.loadRules(Collections.singletonList(ruleB)); | ParamFlowRuleManager.loadRules(Collections.singletonList(ruleB)); | ||||
assertNull("The unused hot param metric should be cleared", ParamFlowSlot.getHotParamMetricForName(resA)); | |||||
assertNull("The unused hot param metric should be cleared", | |||||
ParameterMetricStorage.getParamMetricForResource(resA)); | |||||
} | } | ||||
@Test | @Test | ||||
public void testLoadHotParamRulesAndGet() { | |||||
public void testLoadParamRulesAndGet() { | |||||
final String resA = "abc"; | final String resA = "abc"; | ||||
final String resB = "foo"; | final String resB = "foo"; | ||||
final String resC = "baz"; | final String resC = "baz"; | ||||
@@ -107,4 +108,4 @@ public class ParamFlowRuleManagerTest { | |||||
assertTrue(allRules.contains(ruleC)); | assertTrue(allRules.contains(ruleC)); | ||||
assertTrue(allRules.contains(ruleD)); | assertTrue(allRules.contains(ruleD)); | ||||
} | } | ||||
} | |||||
} |
@@ -82,7 +82,7 @@ public class ParamFlowSlotTest { | |||||
ResourceWrapper resourceWrapper = new StringResourceWrapper(resourceName, EntryType.IN); | ResourceWrapper resourceWrapper = new StringResourceWrapper(resourceName, EntryType.IN); | ||||
paramFlowSlot.entry(null, resourceWrapper, null, 1, false, "abc"); | paramFlowSlot.entry(null, resourceWrapper, null, 1, false, "abc"); | ||||
// The parameter metric instance will not be created. | // The parameter metric instance will not be created. | ||||
assertNull(ParamFlowSlot.getParamMetric(resourceWrapper)); | |||||
assertNull(ParameterMetricStorage.getParamMetric(resourceWrapper)); | |||||
} | } | ||||
@Test | @Test | ||||
@@ -106,7 +106,7 @@ public class ParamFlowSlotTest { | |||||
map.put(argToGo, new AtomicLong(TimeUtil.currentTimeMillis())); | map.put(argToGo, new AtomicLong(TimeUtil.currentTimeMillis())); | ||||
// Insert the mock metric to control pass or block. | // Insert the mock metric to control pass or block. | ||||
ParamFlowSlot.getMetricsMap().put(resourceWrapper, metric); | |||||
ParameterMetricStorage.getMetricsMap().put(resourceWrapper.getName(), metric); | |||||
// The first entry will pass. | // The first entry will pass. | ||||
paramFlowSlot.entry(null, resourceWrapper, null, 1, false, argToGo); | paramFlowSlot.entry(null, resourceWrapper, null, 1, false, argToGo); | ||||
@@ -121,48 +121,16 @@ public class ParamFlowSlotTest { | |||||
fail("The second entry should be blocked"); | fail("The second entry should be blocked"); | ||||
} | } | ||||
@Test | |||||
public void testGetNullParamMetric() { | |||||
assertNull(ParamFlowSlot.getParamMetric(null)); | |||||
} | |||||
@Test | |||||
public void testInitParamMetrics() { | |||||
ParamFlowRule rule = new ParamFlowRule(); | |||||
rule.setParamIdx(1); | |||||
int index = 1; | |||||
String resourceName = "res-" + System.currentTimeMillis(); | |||||
ResourceWrapper resourceWrapper = new StringResourceWrapper(resourceName, EntryType.IN); | |||||
assertNull(ParamFlowSlot.getParamMetric(resourceWrapper)); | |||||
paramFlowSlot.initHotParamMetricsFor(resourceWrapper, rule); | |||||
ParameterMetric metric = ParamFlowSlot.getParamMetric(resourceWrapper); | |||||
assertNotNull(metric); | |||||
assertNotNull(metric.getRuleTimeCounterMap().get(rule)); | |||||
assertNotNull(metric.getThreadCountMap().get(index)); | |||||
// Duplicate init. | |||||
paramFlowSlot.initHotParamMetricsFor(resourceWrapper, rule); | |||||
assertSame(metric, ParamFlowSlot.getParamMetric(resourceWrapper)); | |||||
ParamFlowRule rule2 = new ParamFlowRule(); | |||||
rule2.setParamIdx(1); | |||||
assertSame(metric, ParamFlowSlot.getParamMetric(resourceWrapper)); | |||||
} | |||||
@Before | @Before | ||||
public void setUp() throws Exception { | |||||
public void setUp() { | |||||
ParamFlowRuleManager.loadRules(null); | ParamFlowRuleManager.loadRules(null); | ||||
ParamFlowSlot.getMetricsMap().clear(); | |||||
ParameterMetricStorage.getMetricsMap().clear(); | |||||
} | } | ||||
@After | @After | ||||
public void tearDown() throws Exception { | |||||
public void tearDown() { | |||||
// Clean the metrics map. | // Clean the metrics map. | ||||
ParamFlowSlot.getMetricsMap().clear(); | |||||
ParamFlowRuleManager.loadRules(null); | ParamFlowRuleManager.loadRules(null); | ||||
ParameterMetricStorage.getMetricsMap().clear(); | |||||
} | } | ||||
} | |||||
} |
@@ -1,7 +1,20 @@ | |||||
/* | |||||
* Copyright 1999-2019 Alibaba Group Holding Ltd. | |||||
* | |||||
* Licensed 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 | |||||
* | |||||
* https://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 com.alibaba.csp.sentinel.slots.block.flow.param; | package com.alibaba.csp.sentinel.slots.block.flow.param; | ||||
import static org.junit.Assert.assertEquals; | |||||
import java.util.Random; | import java.util.Random; | ||||
import java.util.concurrent.CountDownLatch; | import java.util.concurrent.CountDownLatch; | ||||
import java.util.concurrent.TimeUnit; | import java.util.concurrent.TimeUnit; | ||||
@@ -19,6 +32,8 @@ import com.alibaba.csp.sentinel.slots.block.RuleConstant; | |||||
import com.alibaba.csp.sentinel.slots.statistic.cache.ConcurrentLinkedHashMapWrapper; | import com.alibaba.csp.sentinel.slots.statistic.cache.ConcurrentLinkedHashMapWrapper; | ||||
import com.alibaba.csp.sentinel.util.TimeUtil; | import com.alibaba.csp.sentinel.util.TimeUtil; | ||||
import static org.junit.Assert.assertEquals; | |||||
/** | /** | ||||
* @author jialiang.linjl | * @author jialiang.linjl | ||||
*/ | */ | ||||
@@ -41,7 +56,7 @@ public class ParamFlowThrottleRateLimitingCheckerTest { | |||||
String valueA = "valueA"; | String valueA = "valueA"; | ||||
ParameterMetric metric = new ParameterMetric(); | ParameterMetric metric = new ParameterMetric(); | ||||
ParamFlowSlot.getMetricsMap().put(resourceWrapper, metric); | |||||
ParameterMetricStorage.getMetricsMap().put(resourceWrapper.getName(), metric); | |||||
metric.getRuleTimeCounterMap().put(rule, new ConcurrentLinkedHashMapWrapper<Object, AtomicLong>(4000)); | metric.getRuleTimeCounterMap().put(rule, new ConcurrentLinkedHashMapWrapper<Object, AtomicLong>(4000)); | ||||
long currentTime = TimeUtil.currentTimeMillis(); | long currentTime = TimeUtil.currentTimeMillis(); | ||||
@@ -85,7 +100,7 @@ public class ParamFlowThrottleRateLimitingCheckerTest { | |||||
final String valueA = "valueA"; | final String valueA = "valueA"; | ||||
ParameterMetric metric = new ParameterMetric(); | ParameterMetric metric = new ParameterMetric(); | ||||
ParamFlowSlot.getMetricsMap().put(resourceWrapper, metric); | |||||
ParameterMetricStorage.getMetricsMap().put(resourceWrapper.getName(), metric); | |||||
metric.getRuleTimeCounterMap().put(rule, new ConcurrentLinkedHashMapWrapper<Object, AtomicLong>(4000)); | metric.getRuleTimeCounterMap().put(rule, new ConcurrentLinkedHashMapWrapper<Object, AtomicLong>(4000)); | ||||
int threadCount = 40; | int threadCount = 40; | ||||
@@ -154,11 +169,11 @@ public class ParamFlowThrottleRateLimitingCheckerTest { | |||||
@Before | @Before | ||||
public void setUp() throws Exception { | public void setUp() throws Exception { | ||||
ParamFlowSlot.getMetricsMap().clear(); | |||||
ParameterMetricStorage.getMetricsMap().clear(); | |||||
} | } | ||||
@After | @After | ||||
public void tearDown() throws Exception { | public void tearDown() throws Exception { | ||||
ParamFlowSlot.getMetricsMap().clear(); | |||||
ParameterMetricStorage.getMetricsMap().clear(); | |||||
} | } | ||||
} | } |
@@ -0,0 +1,72 @@ | |||||
/* | |||||
* Copyright 1999-2019 Alibaba Group Holding Ltd. | |||||
* | |||||
* Licensed 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 | |||||
* | |||||
* https://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 com.alibaba.csp.sentinel.slots.block.flow.param; | |||||
import com.alibaba.csp.sentinel.EntryType; | |||||
import com.alibaba.csp.sentinel.slotchain.ResourceWrapper; | |||||
import com.alibaba.csp.sentinel.slotchain.StringResourceWrapper; | |||||
import org.junit.After; | |||||
import org.junit.Before; | |||||
import org.junit.Test; | |||||
import static org.junit.Assert.*; | |||||
/** | |||||
* @author Eric Zhao | |||||
*/ | |||||
public class ParameterMetricStorageTest { | |||||
@Test | |||||
public void testGetNullParamMetric() { | |||||
assertNull(ParameterMetricStorage.getParamMetric(null)); | |||||
} | |||||
@Test | |||||
public void testInitParamMetrics() { | |||||
ParamFlowRule rule = new ParamFlowRule(); | |||||
rule.setParamIdx(1); | |||||
int index = 1; | |||||
String resourceName = "res-" + System.currentTimeMillis(); | |||||
ResourceWrapper resourceWrapper = new StringResourceWrapper(resourceName, EntryType.IN); | |||||
assertNull(ParameterMetricStorage.getParamMetric(resourceWrapper)); | |||||
ParameterMetricStorage.initParamMetricsFor(resourceWrapper, rule); | |||||
ParameterMetric metric = ParameterMetricStorage.getParamMetric(resourceWrapper); | |||||
assertNotNull(metric); | |||||
assertNotNull(metric.getRuleTimeCounterMap().get(rule)); | |||||
assertNotNull(metric.getThreadCountMap().get(index)); | |||||
// Duplicate init. | |||||
ParameterMetricStorage.initParamMetricsFor(resourceWrapper, rule); | |||||
assertSame(metric, ParameterMetricStorage.getParamMetric(resourceWrapper)); | |||||
ParamFlowRule rule2 = new ParamFlowRule(); | |||||
rule2.setParamIdx(1); | |||||
assertSame(metric, ParameterMetricStorage.getParamMetric(resourceWrapper)); | |||||
} | |||||
@Before | |||||
public void setUp() { | |||||
ParameterMetricStorage.getMetricsMap().clear(); | |||||
} | |||||
@After | |||||
public void tearDown() { | |||||
ParameterMetricStorage.getMetricsMap().clear(); | |||||
} | |||||
} |