Переглянути джерело

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>
master
Eric Zhao 5 роки тому
джерело
коміт
77dec5f845
13 змінених файлів з 378 додано та 186 видалено
  1. +3
    -3
      sentinel-extension/sentinel-parameter-flow-control/src/main/java/com/alibaba/csp/sentinel/slots/block/flow/param/ParamFlowChecker.java
  2. +14
    -41
      sentinel-extension/sentinel-parameter-flow-control/src/main/java/com/alibaba/csp/sentinel/slots/block/flow/param/ParamFlowRuleManager.java
  3. +128
    -2
      sentinel-extension/sentinel-parameter-flow-control/src/main/java/com/alibaba/csp/sentinel/slots/block/flow/param/ParamFlowRuleUtil.java
  4. +2
    -71
      sentinel-extension/sentinel-parameter-flow-control/src/main/java/com/alibaba/csp/sentinel/slots/block/flow/param/ParamFlowSlot.java
  5. +91
    -0
      sentinel-extension/sentinel-parameter-flow-control/src/main/java/com/alibaba/csp/sentinel/slots/block/flow/param/ParameterMetricStorage.java
  6. +2
    -2
      sentinel-extension/sentinel-parameter-flow-control/src/main/java/com/alibaba/csp/sentinel/slots/statistic/ParamFlowStatisticEntryCallback.java
  7. +2
    -2
      sentinel-extension/sentinel-parameter-flow-control/src/main/java/com/alibaba/csp/sentinel/slots/statistic/ParamFlowStatisticExitCallback.java
  8. +6
    -6
      sentinel-extension/sentinel-parameter-flow-control/src/test/java/com/alibaba/csp/sentinel/slots/block/flow/param/ParamFlowCheckerTest.java
  9. +21
    -6
      sentinel-extension/sentinel-parameter-flow-control/src/test/java/com/alibaba/csp/sentinel/slots/block/flow/param/ParamFlowDefaultCheckerTest.java
  10. +9
    -8
      sentinel-extension/sentinel-parameter-flow-control/src/test/java/com/alibaba/csp/sentinel/slots/block/flow/param/ParamFlowRuleManagerTest.java
  11. +7
    -39
      sentinel-extension/sentinel-parameter-flow-control/src/test/java/com/alibaba/csp/sentinel/slots/block/flow/param/ParamFlowSlotTest.java
  12. +21
    -6
      sentinel-extension/sentinel-parameter-flow-control/src/test/java/com/alibaba/csp/sentinel/slots/block/flow/param/ParamFlowThrottleRateLimitingCheckerTest.java
  13. +72
    -0
      sentinel-extension/sentinel-parameter-flow-control/src/test/java/com/alibaba/csp/sentinel/slots/block/flow/param/ParameterMetricStorageTest.java

+ 3
- 3
sentinel-extension/sentinel-parameter-flow-control/src/main/java/com/alibaba/csp/sentinel/slots/block/flow/param/ParamFlowChecker.java Переглянути файл

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


+ 14
- 41
sentinel-extension/sentinel-parameter-flow-control/src/main/java/com/alibaba/csp/sentinel/slots/block/flow/param/ParamFlowRuleManager.java Переглянути файл

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

+ 128
- 2
sentinel-extension/sentinel-parameter-flow-control/src/main/java/com/alibaba/csp/sentinel/slots/block/flow/param/ParamFlowRuleUtil.java Переглянути файл

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

+ 2
- 71
sentinel-extension/sentinel-parameter-flow-control/src/main/java/com/alibaba/csp/sentinel/slots/block/flow/param/ParamFlowSlot.java Переглянути файл

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

+ 91
- 0
sentinel-extension/sentinel-parameter-flow-control/src/main/java/com/alibaba/csp/sentinel/slots/block/flow/param/ParameterMetricStorage.java Переглянути файл

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

+ 2
- 2
sentinel-extension/sentinel-parameter-flow-control/src/main/java/com/alibaba/csp/sentinel/slots/statistic/ParamFlowStatisticEntryCallback.java Переглянути файл

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


+ 2
- 2
sentinel-extension/sentinel-parameter-flow-control/src/main/java/com/alibaba/csp/sentinel/slots/statistic/ParamFlowStatisticExitCallback.java Переглянути файл

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


+ 6
- 6
sentinel-extension/sentinel-parameter-flow-control/src/test/java/com/alibaba/csp/sentinel/slots/block/flow/param/ParamFlowCheckerTest.java Переглянути файл

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

+ 21
- 6
sentinel-extension/sentinel-parameter-flow-control/src/test/java/com/alibaba/csp/sentinel/slots/block/flow/param/ParamFlowDefaultCheckerTest.java Переглянути файл

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

+ 9
- 8
sentinel-extension/sentinel-parameter-flow-control/src/test/java/com/alibaba/csp/sentinel/slots/block/flow/param/ParamFlowRuleManagerTest.java Переглянути файл

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

+ 7
- 39
sentinel-extension/sentinel-parameter-flow-control/src/test/java/com/alibaba/csp/sentinel/slots/block/flow/param/ParamFlowSlotTest.java Переглянути файл

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

+ 21
- 6
sentinel-extension/sentinel-parameter-flow-control/src/test/java/com/alibaba/csp/sentinel/slots/block/flow/param/ParamFlowThrottleRateLimitingCheckerTest.java Переглянути файл

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

+ 72
- 0
sentinel-extension/sentinel-parameter-flow-control/src/test/java/com/alibaba/csp/sentinel/slots/block/flow/param/ParameterMetricStorageTest.java Переглянути файл

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

Завантаження…
Відмінити
Зберегти