- 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 | |||
* @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) { | |||
if (args == null) { | |||
return true; | |||
@@ -249,7 +249,7 @@ final class ParamFlowChecker { | |||
private static ParameterMetric getParameterMetric(ResourceWrapper resourceWrapper) { | |||
// Should not be null. | |||
return ParamFlowSlot.getParamMetric(resourceWrapper); | |||
return ParameterMetricStorage.getParamMetric(resourceWrapper); | |||
} | |||
@SuppressWarnings("unchecked") | |||
@@ -16,7 +16,6 @@ | |||
package com.alibaba.csp.sentinel.slots.block.flow.param; | |||
import java.util.ArrayList; | |||
import java.util.HashSet; | |||
import java.util.List; | |||
import java.util.Map; | |||
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.PropertyListener; | |||
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.StringUtil; | |||
/** | |||
* Manager for frequent ("hot-spot") parameter flow rules. | |||
@@ -39,7 +36,7 @@ import com.alibaba.csp.sentinel.util.StringUtil; | |||
*/ | |||
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 static SentinelProperty<List<ParamFlowRule>> currentProperty = new DynamicSentinelProperty<>(); | |||
@@ -83,7 +80,7 @@ public final class ParamFlowRuleManager { | |||
} | |||
public static boolean hasRules(String resourceName) { | |||
Set<ParamFlowRule> rules = paramFlowRules.get(resourceName); | |||
List<ParamFlowRule> rules = paramFlowRules.get(resourceName); | |||
return rules != null && !rules.isEmpty(); | |||
} | |||
@@ -94,7 +91,7 @@ public final class ParamFlowRuleManager { | |||
*/ | |||
public static List<ParamFlowRule> getRules() { | |||
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()); | |||
} | |||
return rules; | |||
@@ -104,61 +101,38 @@ public final class ParamFlowRuleManager { | |||
@Override | |||
public void configUpdate(List<ParamFlowRule> list) { | |||
Map<String, Set<ParamFlowRule>> rules = aggregateHotParamRules(list); | |||
Map<String, List<ParamFlowRule>> rules = aggregateAndPrepareParamRules(list); | |||
if (rules != null) { | |||
paramFlowRules.clear(); | |||
paramFlowRules.putAll(rules); | |||
} | |||
RecordLog.info("[ParamFlowRuleManager] Hot spot parameter flow rules received: " + paramFlowRules); | |||
RecordLog.info("[ParamFlowRuleManager] Parameter flow rules received: " + paramFlowRules); | |||
} | |||
@Override | |||
public void configLoad(List<ParamFlowRule> list) { | |||
Map<String, Set<ParamFlowRule>> rules = aggregateHotParamRules(list); | |||
Map<String, List<ParamFlowRule>> rules = aggregateAndPrepareParamRules(list); | |||
if (rules != null) { | |||
paramFlowRules.clear(); | |||
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. | |||
ParamFlowSlot.getMetricsMap().clear(); | |||
ParameterMetricStorage.getMetricsMap().clear(); | |||
RecordLog.info("[ParamFlowRuleManager] No parameter flow rules, clearing all parameter metrics"); | |||
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(); | |||
for (String resource : previousResources) { | |||
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.HashMap; | |||
import java.util.HashSet; | |||
import java.util.List; | |||
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.slots.block.RuleConstant; | |||
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.function.Function; | |||
import com.alibaba.csp.sentinel.util.function.Predicate; | |||
/** | |||
* @author Eric Zhao | |||
*/ | |||
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) { | |||
return rule != null && !StringUtil.isBlank(rule.getResource()) && rule.getCount() >= 0 | |||
&& rule.getGrade() >= 0 && rule.getParamIdx() != null | |||
@@ -55,6 +69,11 @@ public final class ParamFlowRuleUtil { | |||
return id != null && id > 0; | |||
} | |||
/** | |||
* Fill the parameter rule with parsed items. | |||
* | |||
* @param rule valid parameter rule | |||
*/ | |||
public static void fillExceptionFlowItems(ParamFlowRule rule) { | |||
if (rule != 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) { | |||
Map<Object, Integer> itemMap = new HashMap<Object, Integer>(); | |||
if (items == null || items.isEmpty()) { | |||
return itemMap; | |||
return new HashMap<>(); | |||
} | |||
Map<Object, Integer> itemMap = new HashMap<>(items.size()); | |||
for (ParamFlowItem item : items) { | |||
// Value should not be null. | |||
Object value; | |||
@@ -120,5 +239,12 @@ public final class ParamFlowRuleUtil { | |||
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() {} | |||
} |
@@ -16,18 +16,12 @@ | |||
package com.alibaba.csp.sentinel.slots.block.flow.param; | |||
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.log.RecordLog; | |||
import com.alibaba.csp.sentinel.node.DefaultNode; | |||
import com.alibaba.csp.sentinel.slotchain.AbstractLinkedProcessorSlot; | |||
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.util.StringUtil; | |||
/** | |||
* 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> { | |||
private static final Map<ResourceWrapper, ParameterMetric> metricsMap = new ConcurrentHashMap<>(); | |||
/** | |||
* Lock for a specific resource. | |||
*/ | |||
private final Object LOCK = new Object(); | |||
@Override | |||
public void entry(Context context, ResourceWrapper resourceWrapper, DefaultNode node, int count, | |||
boolean prioritized, Object... args) throws Throwable { | |||
@@ -68,7 +55,7 @@ public class ParamFlowSlot extends AbstractLinkedProcessorSlot<DefaultNode> { | |||
if (-paramIdx <= length) { | |||
rule.setParamIdx(length + paramIdx); | |||
} 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); | |||
} | |||
} | |||
@@ -87,7 +74,7 @@ public class ParamFlowSlot extends AbstractLinkedProcessorSlot<DefaultNode> { | |||
applyRealParamIdx(rule, args.length); | |||
// Initialize the parameter metrics. | |||
initHotParamMetricsFor(resourceWrapper, rule); | |||
ParameterMetricStorage.initParamMetricsFor(resourceWrapper, rule); | |||
if (!ParamFlowChecker.passCheck(resourceWrapper, rule, count, args)) { | |||
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.ResourceWrapper; | |||
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.ParameterMetricStorage; | |||
/** | |||
* @author Eric Zhao | |||
@@ -32,7 +32,7 @@ public class ParamFlowStatisticEntryCallback implements ProcessorSlotEntryCallba | |||
@Override | |||
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. | |||
ParameterMetric parameterMetric = ParamFlowSlot.getParamMetric(resourceWrapper); | |||
ParameterMetric parameterMetric = ParameterMetricStorage.getParamMetric(resourceWrapper); | |||
if (parameterMetric != null) { | |||
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.slotchain.ProcessorSlotExitCallback; | |||
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.ParameterMetricStorage; | |||
/** | |||
* @author Eric Zhao | |||
@@ -30,7 +30,7 @@ public class ParamFlowStatisticExitCallback implements ProcessorSlotExitCallback | |||
@Override | |||
public void onExit(Context context, ResourceWrapper resourceWrapper, int count, Object... args) { | |||
if (context.getCurEntry().getError() == null) { | |||
ParameterMetric parameterMetric = ParamFlowSlot.getParamMetric(resourceWrapper); | |||
ParameterMetric parameterMetric = ParameterMetricStorage.getParamMetric(resourceWrapper); | |||
if (parameterMetric != null) { | |||
parameterMetric.decreaseThreadCount(args); | |||
@@ -90,7 +90,7 @@ public class ParamFlowCheckerTest { | |||
rule.setParsedHotItems(map); | |||
ParameterMetric metric = new ParameterMetric(); | |||
ParamFlowSlot.getMetricsMap().put(resourceWrapper, metric); | |||
ParameterMetricStorage.getMetricsMap().put(resourceWrapper.getName(), metric); | |||
metric.getRuleTimeCounterMap().put(rule, new ConcurrentLinkedHashMapWrapper<Object, AtomicLong>(4000)); | |||
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, valueC)).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)); | |||
assertFalse(ParamFlowChecker.passSingleValueCheck(resourceWrapper, rule, 1, valueB)); | |||
@@ -158,7 +158,7 @@ public class ParamFlowCheckerTest { | |||
String v1 = "a", v2 = "B", v3 = "Cc"; | |||
List<String> list = Arrays.asList(v1, v2, v3); | |||
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.getRuleTokenCounterMap().put(rule, new ConcurrentLinkedHashMapWrapper<Object, AtomicInteger>(4000)); | |||
@@ -181,7 +181,7 @@ public class ParamFlowCheckerTest { | |||
String v1 = "a", v2 = "B", v3 = "Cc"; | |||
Object arr = new String[] {v1, v2, v3}; | |||
ParameterMetric metric = new ParameterMetric(); | |||
ParamFlowSlot.getMetricsMap().put(resourceWrapper, metric); | |||
ParameterMetricStorage.getMetricsMap().put(resourceWrapper.getName(), metric); | |||
metric.getRuleTimeCounterMap().put(rule, new ConcurrentLinkedHashMapWrapper<Object, AtomicLong>(4000)); | |||
assertTrue(ParamFlowChecker.passCheck(resourceWrapper, rule, 1, arr)); | |||
@@ -190,11 +190,11 @@ public class ParamFlowCheckerTest { | |||
@Before | |||
public void setUp() throws Exception { | |||
ParamFlowSlot.getMetricsMap().clear(); | |||
ParameterMetricStorage.getMetricsMap().clear(); | |||
} | |||
@After | |||
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; | |||
import static org.junit.Assert.assertEquals; | |||
@@ -41,7 +56,7 @@ public class ParamFlowDefaultCheckerTest extends AbstractTimeBasedTest { | |||
String valueA = "valueA"; | |||
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.getRuleTokenCounterMap().put(rule, | |||
new ConcurrentLinkedHashMapWrapper<Object, AtomicInteger>(4000)); | |||
@@ -81,7 +96,7 @@ public class ParamFlowDefaultCheckerTest extends AbstractTimeBasedTest { | |||
String valueA = "valueA"; | |||
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.getRuleTokenCounterMap().put(rule, | |||
new ConcurrentLinkedHashMapWrapper<Object, AtomicInteger>(4000)); | |||
@@ -151,7 +166,7 @@ public class ParamFlowDefaultCheckerTest extends AbstractTimeBasedTest { | |||
String valueA = "helloWorld"; | |||
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.getRuleTokenCounterMap().put(rule, | |||
new ConcurrentLinkedHashMapWrapper<Object, AtomicInteger>(4000)); | |||
@@ -204,7 +219,7 @@ public class ParamFlowDefaultCheckerTest extends AbstractTimeBasedTest { | |||
final String valueA = "valueA"; | |||
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.getRuleTokenCounterMap().put(rule, | |||
new ConcurrentLinkedHashMapWrapper<Object, AtomicInteger>(4000)); | |||
@@ -270,11 +285,11 @@ public class ParamFlowDefaultCheckerTest extends AbstractTimeBasedTest { | |||
@Before | |||
public void setUp() throws Exception { | |||
ParamFlowSlot.getMetricsMap().clear(); | |||
ParameterMetricStorage.getMetricsMap().clear(); | |||
} | |||
@After | |||
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.List; | |||
import com.alibaba.csp.sentinel.EntryType; | |||
import com.alibaba.csp.sentinel.slotchain.StringResourceWrapper; | |||
import com.alibaba.csp.sentinel.slots.block.RuleConstant; | |||
import org.junit.After; | |||
@@ -40,33 +38,36 @@ public class ParamFlowRuleManagerTest { | |||
@Before | |||
public void setUp() { | |||
ParamFlowRuleManager.loadRules(null); | |||
ParameterMetricStorage.getMetricsMap().clear(); | |||
} | |||
@After | |||
public void tearDown() { | |||
ParamFlowRuleManager.loadRules(null); | |||
ParameterMetricStorage.getMetricsMap().clear(); | |||
} | |||
@Test | |||
public void testLoadHotParamRulesClearingUnusedMetrics() { | |||
public void testLoadParamRulesClearingUnusedMetrics() { | |||
final String resA = "resA"; | |||
ParamFlowRule ruleA = new ParamFlowRule(resA) | |||
.setCount(1) | |||
.setParamIdx(0); | |||
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"; | |||
ParamFlowRule ruleB = new ParamFlowRule(resB) | |||
.setCount(2) | |||
.setParamIdx(1); | |||
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 | |||
public void testLoadHotParamRulesAndGet() { | |||
public void testLoadParamRulesAndGet() { | |||
final String resA = "abc"; | |||
final String resB = "foo"; | |||
final String resC = "baz"; | |||
@@ -107,4 +108,4 @@ public class ParamFlowRuleManagerTest { | |||
assertTrue(allRules.contains(ruleC)); | |||
assertTrue(allRules.contains(ruleD)); | |||
} | |||
} | |||
} |
@@ -82,7 +82,7 @@ public class ParamFlowSlotTest { | |||
ResourceWrapper resourceWrapper = new StringResourceWrapper(resourceName, EntryType.IN); | |||
paramFlowSlot.entry(null, resourceWrapper, null, 1, false, "abc"); | |||
// The parameter metric instance will not be created. | |||
assertNull(ParamFlowSlot.getParamMetric(resourceWrapper)); | |||
assertNull(ParameterMetricStorage.getParamMetric(resourceWrapper)); | |||
} | |||
@Test | |||
@@ -106,7 +106,7 @@ public class ParamFlowSlotTest { | |||
map.put(argToGo, new AtomicLong(TimeUtil.currentTimeMillis())); | |||
// 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. | |||
paramFlowSlot.entry(null, resourceWrapper, null, 1, false, argToGo); | |||
@@ -121,48 +121,16 @@ public class ParamFlowSlotTest { | |||
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 | |||
public void setUp() throws Exception { | |||
public void setUp() { | |||
ParamFlowRuleManager.loadRules(null); | |||
ParamFlowSlot.getMetricsMap().clear(); | |||
ParameterMetricStorage.getMetricsMap().clear(); | |||
} | |||
@After | |||
public void tearDown() throws Exception { | |||
public void tearDown() { | |||
// Clean the metrics map. | |||
ParamFlowSlot.getMetricsMap().clear(); | |||
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; | |||
import static org.junit.Assert.assertEquals; | |||
import java.util.Random; | |||
import java.util.concurrent.CountDownLatch; | |||
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.util.TimeUtil; | |||
import static org.junit.Assert.assertEquals; | |||
/** | |||
* @author jialiang.linjl | |||
*/ | |||
@@ -41,7 +56,7 @@ public class ParamFlowThrottleRateLimitingCheckerTest { | |||
String valueA = "valueA"; | |||
ParameterMetric metric = new ParameterMetric(); | |||
ParamFlowSlot.getMetricsMap().put(resourceWrapper, metric); | |||
ParameterMetricStorage.getMetricsMap().put(resourceWrapper.getName(), metric); | |||
metric.getRuleTimeCounterMap().put(rule, new ConcurrentLinkedHashMapWrapper<Object, AtomicLong>(4000)); | |||
long currentTime = TimeUtil.currentTimeMillis(); | |||
@@ -85,7 +100,7 @@ public class ParamFlowThrottleRateLimitingCheckerTest { | |||
final String valueA = "valueA"; | |||
ParameterMetric metric = new ParameterMetric(); | |||
ParamFlowSlot.getMetricsMap().put(resourceWrapper, metric); | |||
ParameterMetricStorage.getMetricsMap().put(resourceWrapper.getName(), metric); | |||
metric.getRuleTimeCounterMap().put(rule, new ConcurrentLinkedHashMapWrapper<Object, AtomicLong>(4000)); | |||
int threadCount = 40; | |||
@@ -154,11 +169,11 @@ public class ParamFlowThrottleRateLimitingCheckerTest { | |||
@Before | |||
public void setUp() throws Exception { | |||
ParamFlowSlot.getMetricsMap().clear(); | |||
ParameterMetricStorage.getMetricsMap().clear(); | |||
} | |||
@After | |||
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(); | |||
} | |||
} |