Separate parameter metric storage from ParamFlowSlot and improve ParamFlowRuleUtil

- 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>
This commit is contained in:
Eric Zhao 2019-05-11 22:18:21 +08:00
parent 54da16d304
commit 77dec5f845
13 changed files with 380 additions and 188 deletions

View File

@ -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")

View File

@ -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() {}
}

View File

@ -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 {
}
}
static Map<Object, Integer> parseHotItems(List<ParamFlowItem> items) {
Map<Object, Integer> itemMap = new HashMap<Object, Integer>();
if (items == null || items.isEmpty()) {
return itemMap;
/**
* 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) {
if (items == null || items.isEmpty()) {
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() {}
}

View File

@ -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;
}
}

View File

@ -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() {}
}

View File

@ -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);

View File

@ -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);

View File

@ -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();
}
}

View File

@ -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();
}
}

View File

@ -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));
}
}
}

View File

@ -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();
}
}
}

View File

@ -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();
}
}

View File

@ -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();
}
}