rules = ruleProvider.apply(resource.getName());
+ if (rules != null) {
+ for (FlowRule rule : rules) {
+ if (!canPassCheck(rule, context, node, count, prioritized)) {
+ throw new FlowException(rule.getLimitApp(), rule);
+ }
+ }
+ }
}
- static boolean passCheck(/*@NonNull*/ FlowRule rule, Context context, DefaultNode node, int acquireCount,
- boolean prioritized) {
+ public boolean canPassCheck(/*@NonNull*/ FlowRule rule, Context context, DefaultNode node,
+ int acquireCount) {
+ return canPassCheck(rule, context, node, acquireCount, false);
+ }
+
+ public boolean canPassCheck(/*@NonNull*/ FlowRule rule, Context context, DefaultNode node, int acquireCount,
+ boolean prioritized) {
String limitApp = rule.getLimitApp();
if (limitApp == null) {
return true;
@@ -162,8 +183,9 @@ private static TokenService pickClusterService() {
return null;
}
- private static boolean applyTokenResult(/*@NonNull*/ TokenResult result, FlowRule rule, Context context, DefaultNode node,
- int acquireCount, boolean prioritized) {
+ private static boolean applyTokenResult(/*@NonNull*/ TokenResult result, FlowRule rule, Context context,
+ DefaultNode node,
+ int acquireCount, boolean prioritized) {
switch (result.getStatus()) {
case TokenResultStatus.OK:
return true;
@@ -185,6 +207,4 @@ private static boolean applyTokenResult(/*@NonNull*/ TokenResult result, FlowRul
return false;
}
}
-
- private FlowRuleChecker() {}
}
\ No newline at end of file
diff --git a/sentinel-core/src/main/java/com/alibaba/csp/sentinel/slots/block/flow/FlowSlot.java b/sentinel-core/src/main/java/com/alibaba/csp/sentinel/slots/block/flow/FlowSlot.java
index 179ea8caa3..d05d51c8e7 100755
--- a/sentinel-core/src/main/java/com/alibaba/csp/sentinel/slots/block/flow/FlowSlot.java
+++ b/sentinel-core/src/main/java/com/alibaba/csp/sentinel/slots/block/flow/FlowSlot.java
@@ -15,15 +15,18 @@
*/
package com.alibaba.csp.sentinel.slots.block.flow;
-import java.util.List;
-import java.util.Map;
-
import com.alibaba.csp.sentinel.context.Context;
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.slots.block.BlockException;
import com.alibaba.csp.sentinel.spi.SpiOrder;
+import com.alibaba.csp.sentinel.util.AssertUtil;
+import com.alibaba.csp.sentinel.util.function.Function;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
/**
*
@@ -137,6 +140,23 @@
@SpiOrder(-2000)
public class FlowSlot extends AbstractLinkedProcessorSlot {
+ private final FlowRuleChecker checker;
+
+ public FlowSlot() {
+ this(new FlowRuleChecker());
+ }
+
+ /**
+ * Package-private for test.
+ *
+ * @param checker flow rule checker
+ * @since 1.6.1
+ */
+ FlowSlot(FlowRuleChecker checker) {
+ AssertUtil.notNull(checker, "flow checker should not be null");
+ this.checker = checker;
+ }
+
@Override
public void entry(Context context, ResourceWrapper resourceWrapper, DefaultNode node, int count,
boolean prioritized, Object... args) throws Throwable {
@@ -145,26 +165,22 @@ public void entry(Context context, ResourceWrapper resourceWrapper, DefaultNode
fireEntry(context, resourceWrapper, node, count, prioritized, args);
}
- void checkFlow(ResourceWrapper resource, Context context, DefaultNode node, int count, boolean prioritized) throws BlockException {
- // Flow rule map cannot be null.
- Map> flowRules = FlowRuleManager.getFlowRuleMap();
-
- List rules = flowRules.get(resource.getName());
- if (rules != null) {
- for (FlowRule rule : rules) {
- if (!canPassCheck(rule, context, node, count, prioritized)) {
- throw new FlowException(rule.getLimitApp(), rule);
- }
- }
- }
- }
-
- boolean canPassCheck(FlowRule rule, Context context, DefaultNode node, int count, boolean prioritized) {
- return FlowRuleChecker.passCheck(rule, context, node, count, prioritized);
+ void checkFlow(ResourceWrapper resource, Context context, DefaultNode node, int count, boolean prioritized)
+ throws BlockException {
+ checker.checkFlow(ruleProvider, resource, context, node, count, prioritized);
}
@Override
public void exit(Context context, ResourceWrapper resourceWrapper, int count, Object... args) {
fireExit(context, resourceWrapper, count, args);
}
+
+ private final Function> ruleProvider = new Function>() {
+ @Override
+ public Collection apply(String resource) {
+ // Flow rule map should not be null.
+ Map> flowRules = FlowRuleManager.getFlowRuleMap();
+ return flowRules.get(resource);
+ }
+ };
}
diff --git a/sentinel-core/src/main/java/com/alibaba/csp/sentinel/slots/nodeselector/NodeSelectorSlot.java b/sentinel-core/src/main/java/com/alibaba/csp/sentinel/slots/nodeselector/NodeSelectorSlot.java
index a2dd085e67..fb26c6680b 100755
--- a/sentinel-core/src/main/java/com/alibaba/csp/sentinel/slots/nodeselector/NodeSelectorSlot.java
+++ b/sentinel-core/src/main/java/com/alibaba/csp/sentinel/slots/nodeselector/NodeSelectorSlot.java
@@ -15,9 +15,6 @@
*/
package com.alibaba.csp.sentinel.slots.nodeselector;
-import java.util.HashMap;
-import java.util.Map;
-
import com.alibaba.csp.sentinel.context.Context;
import com.alibaba.csp.sentinel.context.ContextUtil;
import com.alibaba.csp.sentinel.node.ClusterNode;
@@ -27,6 +24,9 @@
import com.alibaba.csp.sentinel.slotchain.ResourceWrapper;
import com.alibaba.csp.sentinel.spi.SpiOrder;
+import java.util.HashMap;
+import java.util.Map;
+
/**
*
* This class will try to build the calling traces via
@@ -162,9 +162,10 @@ public void entry(Context context, ResourceWrapper resourceWrapper, Object obj,
cacheMap.putAll(map);
cacheMap.put(context.getName(), node);
map = cacheMap;
+ // Build invocation tree
+ ((DefaultNode) context.getLastNode()).addChild(node);
}
- // Build invocation tree
- ((DefaultNode)context.getLastNode()).addChild(node);
+
}
}
diff --git a/sentinel-core/src/main/java/com/alibaba/csp/sentinel/slots/statistic/base/LeapArray.java b/sentinel-core/src/main/java/com/alibaba/csp/sentinel/slots/statistic/base/LeapArray.java
index 58a0dce0e3..2bba544be1 100755
--- a/sentinel-core/src/main/java/com/alibaba/csp/sentinel/slots/statistic/base/LeapArray.java
+++ b/sentinel-core/src/main/java/com/alibaba/csp/sentinel/slots/statistic/base/LeapArray.java
@@ -209,8 +209,7 @@ public WindowWrap getPreviousWindow(long timeMillis) {
if (timeMillis < 0) {
return null;
}
- long timeId = (timeMillis - windowLengthInMs) / windowLengthInMs;
- int idx = (int)(timeId % array.length());
+ int idx = calculateTimeIdx(timeMillis - windowLengthInMs);
timeMillis = timeMillis - windowLengthInMs;
WindowWrap wrap = array.get(idx);
diff --git a/sentinel-core/src/main/java/com/alibaba/csp/sentinel/slots/statistic/metric/ArrayMetric.java b/sentinel-core/src/main/java/com/alibaba/csp/sentinel/slots/statistic/metric/ArrayMetric.java
index f4c2a073d2..8647d99461 100755
--- a/sentinel-core/src/main/java/com/alibaba/csp/sentinel/slots/statistic/metric/ArrayMetric.java
+++ b/sentinel-core/src/main/java/com/alibaba/csp/sentinel/slots/statistic/metric/ArrayMetric.java
@@ -234,8 +234,8 @@ public void debug() {
@Override
public long previousWindowBlock() {
- WindowWrap wrap = data.currentWindow();
- wrap = data.getPreviousWindow();
+ data.currentWindow();
+ WindowWrap wrap = data.getPreviousWindow();
if (wrap == null) {
return 0;
}
@@ -244,8 +244,8 @@ public long previousWindowBlock() {
@Override
public long previousWindowPass() {
- WindowWrap wrap = data.currentWindow();
- wrap = data.getPreviousWindow();
+ data.currentWindow();
+ WindowWrap wrap = data.getPreviousWindow();
if (wrap == null) {
return 0;
}
diff --git a/sentinel-core/src/main/java/com/alibaba/csp/sentinel/slots/system/SystemRuleManager.java b/sentinel-core/src/main/java/com/alibaba/csp/sentinel/slots/system/SystemRuleManager.java
index 99b93a931d..7a6091fe57 100755
--- a/sentinel-core/src/main/java/com/alibaba/csp/sentinel/slots/system/SystemRuleManager.java
+++ b/sentinel-core/src/main/java/com/alibaba/csp/sentinel/slots/system/SystemRuleManager.java
@@ -222,6 +222,7 @@ protected void restoreSetting() {
qps = Double.MAX_VALUE;
highestSystemLoadIsSet = false;
+ highestCpuUsageIsSet = false;
maxRtIsSet = false;
maxThreadIsSet = false;
qpsIsSet = false;
@@ -240,6 +241,10 @@ public static double getHighestSystemLoad() {
public static void setHighestSystemLoad(double highestSystemLoad) {
SystemRuleManager.highestSystemLoad = highestSystemLoad;
}
+
+ public static double getCpuUsageThreshold() {
+ return highestCpuUsage;
+ }
public static void loadSystemConf(SystemRule rule) {
boolean checkStatus = false;
@@ -342,4 +347,4 @@ public static double getCurrentSystemAvgLoad() {
public static double getCurrentCpuUsage() {
return statusListener.getCpuUsage();
}
-}
+}
\ No newline at end of file
diff --git a/sentinel-core/src/main/java/com/alibaba/csp/sentinel/slots/system/SystemStatusListener.java b/sentinel-core/src/main/java/com/alibaba/csp/sentinel/slots/system/SystemStatusListener.java
index 8cf45a37c6..e02f0c858b 100755
--- a/sentinel-core/src/main/java/com/alibaba/csp/sentinel/slots/system/SystemStatusListener.java
+++ b/sentinel-core/src/main/java/com/alibaba/csp/sentinel/slots/system/SystemStatusListener.java
@@ -33,8 +33,6 @@ public class SystemStatusListener implements Runnable {
volatile String reason = StringUtil.EMPTY;
- static final int processor = ManagementFactory.getOperatingSystemMXBean().getAvailableProcessors();
-
public double getSystemAverageLoad() {
return currentLoad;
}
@@ -46,10 +44,6 @@ public double getCpuUsage() {
@Override
public void run() {
try {
- if (!SystemRuleManager.getCheckSystemStatus()) {
- return;
- }
-
OperatingSystemMXBean osBean = ManagementFactory.getPlatformMXBean(OperatingSystemMXBean.class);
currentLoad = osBean.getSystemLoadAverage();
/**
diff --git a/sentinel-core/src/main/resources/META-INF/services/com.alibaba.csp.sentinel.init.InitFunc b/sentinel-core/src/main/resources/META-INF/services/com.alibaba.csp.sentinel.init.InitFunc
new file mode 100644
index 0000000000..68a6ac77f7
--- /dev/null
+++ b/sentinel-core/src/main/resources/META-INF/services/com.alibaba.csp.sentinel.init.InitFunc
@@ -0,0 +1 @@
+com.alibaba.csp.sentinel.metric.extension.MetricCallbackInit
\ No newline at end of file
diff --git a/sentinel-core/src/test/java/com/alibaba/csp/sentinel/TracerTest.java b/sentinel-core/src/test/java/com/alibaba/csp/sentinel/TracerTest.java
new file mode 100644
index 0000000000..4b2352e1b8
--- /dev/null
+++ b/sentinel-core/src/test/java/com/alibaba/csp/sentinel/TracerTest.java
@@ -0,0 +1,70 @@
+package com.alibaba.csp.sentinel;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+/**
+ * @author Carpenter Lee
+ */
+public class TracerTest extends Tracer {
+
+ @Test
+ public void setExceptionsToTrace() {
+ Tracer.ignoreClasses = null;
+ Tracer.traceClasses = null;
+ Tracer.setExceptionsToTrace(TraceException.class, TraceException2.class);
+ Assert.assertTrue(Tracer.shouldTrace(new TraceException2()));
+ Assert.assertTrue(Tracer.shouldTrace(new TraceExceptionSub()));
+ Assert.assertFalse(Tracer.shouldTrace(new Exception()));
+ }
+
+ @Test
+ public void setExceptionsToIgnore() {
+ Tracer.ignoreClasses = null;
+ Tracer.traceClasses = null;
+ Tracer.setExceptionsToIgnore(IgnoreException.class, IgnoreException2.class);
+ Assert.assertFalse(Tracer.shouldTrace(new IgnoreException()));
+ Assert.assertFalse(Tracer.shouldTrace(new IgnoreExceptionSub()));
+ Assert.assertTrue(Tracer.shouldTrace(new Exception()));
+ }
+
+ @Test
+ public void testBoth() {
+ Tracer.ignoreClasses = null;
+ Tracer.traceClasses = null;
+ Tracer.setExceptionsToTrace(TraceException.class, TraceException2.class, BothException.class);
+ Tracer.setExceptionsToIgnore(IgnoreException.class, IgnoreException2.class, BothException.class);
+ Assert.assertFalse(Tracer.shouldTrace(new IgnoreException()));
+ Assert.assertFalse(Tracer.shouldTrace(new BothException()));
+ Assert.assertTrue(Tracer.shouldTrace(new TraceException()));
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testNull() {
+ Tracer.setExceptionsToTrace(null);
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testNull1() {
+ Tracer.setExceptionsToTrace(TraceException.class, null);
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testNull2() {
+ Tracer.setExceptionsToIgnore(IgnoreException.class, null);
+ }
+
+ private class TraceException extends Exception {}
+
+ private class TraceException2 extends Exception {}
+
+ private class TraceExceptionSub extends TraceException {}
+
+ private class IgnoreException extends Exception {}
+
+ private class IgnoreException2 extends Exception {}
+
+ private class IgnoreExceptionSub extends IgnoreException {}
+
+ private class BothException extends Exception {}
+}
\ No newline at end of file
diff --git a/sentinel-core/src/test/java/com/alibaba/csp/sentinel/metric/extension/callback/FakeMetricExtension.java b/sentinel-core/src/test/java/com/alibaba/csp/sentinel/metric/extension/callback/FakeMetricExtension.java
new file mode 100644
index 0000000000..f9ac290830
--- /dev/null
+++ b/sentinel-core/src/test/java/com/alibaba/csp/sentinel/metric/extension/callback/FakeMetricExtension.java
@@ -0,0 +1,51 @@
+package com.alibaba.csp.sentinel.metric.extension.callback;
+
+import com.alibaba.csp.sentinel.metric.extension.MetricExtension;
+import com.alibaba.csp.sentinel.slots.block.BlockException;
+
+/**
+ * @author Carpenter Lee
+ */
+class FakeMetricExtension implements MetricExtension {
+ long pass = 0;
+ long block = 0;
+ long success = 0;
+ long exception = 0;
+ long rt = 0;
+ long thread = 0;
+
+ @Override
+ public void addPass(String resource, int n, Object... args) {
+ pass += n;
+ }
+
+ @Override
+ public void addBlock(String resource, int n, String origin, BlockException ex, Object... args) {
+ block += n;
+ }
+
+ @Override
+ public void addSuccess(String resource, int n, Object... args) {
+ success += n;
+ }
+
+ @Override
+ public void addException(String resource, int n, Throwable t) {
+ exception += n;
+ }
+
+ @Override
+ public void addRt(String resource, long rt, Object... args) {
+ this.rt += rt;
+ }
+
+ @Override
+ public void increaseThreadNum(String resource, Object... args) {
+ thread++;
+ }
+
+ @Override
+ public void decreaseThreadNum(String resource, Object... args) {
+ thread--;
+ }
+}
diff --git a/sentinel-core/src/test/java/com/alibaba/csp/sentinel/metric/extension/callback/MetricEntryCallbackTest.java b/sentinel-core/src/test/java/com/alibaba/csp/sentinel/metric/extension/callback/MetricEntryCallbackTest.java
new file mode 100644
index 0000000000..f1972c8e9e
--- /dev/null
+++ b/sentinel-core/src/test/java/com/alibaba/csp/sentinel/metric/extension/callback/MetricEntryCallbackTest.java
@@ -0,0 +1,48 @@
+package com.alibaba.csp.sentinel.metric.extension.callback;
+
+import com.alibaba.csp.sentinel.EntryType;
+import com.alibaba.csp.sentinel.context.Context;
+import com.alibaba.csp.sentinel.metric.extension.MetricExtensionProvider;
+import com.alibaba.csp.sentinel.slotchain.StringResourceWrapper;
+import com.alibaba.csp.sentinel.slots.block.flow.FlowException;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+/**
+ * @author Carpenter Lee
+ */
+public class MetricEntryCallbackTest {
+
+ @Test
+ public void onPass() throws Exception {
+ FakeMetricExtension extension = new FakeMetricExtension();
+ MetricExtensionProvider.addMetricExtension(extension);
+
+ MetricEntryCallback entryCallback = new MetricEntryCallback();
+ StringResourceWrapper resourceWrapper = new StringResourceWrapper("resource", EntryType.OUT);
+ int count = 2;
+ Object[] args = {"args1", "args2"};
+ entryCallback.onPass(null, resourceWrapper, null, count, args);
+ Assert.assertEquals(extension.pass, count);
+ Assert.assertEquals(extension.thread, 1);
+ }
+
+ @Test
+ public void onBlocked() throws Exception {
+ FakeMetricExtension extension = new FakeMetricExtension();
+ MetricExtensionProvider.addMetricExtension(extension);
+
+ MetricEntryCallback entryCallback = new MetricEntryCallback();
+ StringResourceWrapper resourceWrapper = new StringResourceWrapper("resource", EntryType.OUT);
+ Context context = mock(Context.class);
+ when(context.getOrigin()).thenReturn("origin1");
+ int count = 2;
+ Object[] args = {"args1", "args2"};
+ entryCallback.onBlocked(new FlowException("xx"), context, resourceWrapper, null, count, args);
+ Assert.assertEquals(extension.block, count);
+ }
+}
\ No newline at end of file
diff --git a/sentinel-core/src/test/java/com/alibaba/csp/sentinel/metric/extension/callback/MetricExitCallbackTest.java b/sentinel-core/src/test/java/com/alibaba/csp/sentinel/metric/extension/callback/MetricExitCallbackTest.java
new file mode 100644
index 0000000000..8bf2b89520
--- /dev/null
+++ b/sentinel-core/src/test/java/com/alibaba/csp/sentinel/metric/extension/callback/MetricExitCallbackTest.java
@@ -0,0 +1,43 @@
+package com.alibaba.csp.sentinel.metric.extension.callback;
+
+import com.alibaba.csp.sentinel.Entry;
+import com.alibaba.csp.sentinel.EntryType;
+import com.alibaba.csp.sentinel.context.Context;
+import com.alibaba.csp.sentinel.metric.extension.MetricExtensionProvider;
+import com.alibaba.csp.sentinel.slotchain.StringResourceWrapper;
+import com.alibaba.csp.sentinel.util.TimeUtil;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+/**
+ * @author Carpenter Lee
+ */
+public class MetricExitCallbackTest {
+
+ @Test
+ public void onExit() {
+ FakeMetricExtension extension = new FakeMetricExtension();
+ MetricExtensionProvider.addMetricExtension(extension);
+
+ MetricExitCallback exitCallback = new MetricExitCallback();
+ StringResourceWrapper resourceWrapper = new StringResourceWrapper("resource", EntryType.OUT);
+ int count = 2;
+ Object[] args = {"args1", "args2"};
+ extension.rt = 20;
+ extension.success = 6;
+ extension.thread = 10;
+ Context context = mock(Context.class);
+ Entry entry = mock(Entry.class);
+ when(entry.getError()).thenReturn(null);
+ when(entry.getCreateTime()).thenReturn(TimeUtil.currentTimeMillis() - 100);
+ when(context.getCurEntry()).thenReturn(entry);
+ exitCallback.onExit(context, resourceWrapper, count, args);
+ Assert.assertEquals(120, extension.rt, 10);
+ Assert.assertEquals(extension.success, 6 + count);
+ Assert.assertEquals(extension.thread, 10 - 1);
+ }
+}
\ No newline at end of file
diff --git a/sentinel-core/src/test/java/com/alibaba/csp/sentinel/node/StatisticNodeTest.java b/sentinel-core/src/test/java/com/alibaba/csp/sentinel/node/StatisticNodeTest.java
index 44674dd14c..c34b8bf919 100644
--- a/sentinel-core/src/test/java/com/alibaba/csp/sentinel/node/StatisticNodeTest.java
+++ b/sentinel-core/src/test/java/com/alibaba/csp/sentinel/node/StatisticNodeTest.java
@@ -17,17 +17,23 @@
import com.alibaba.csp.sentinel.Constants;
import com.alibaba.csp.sentinel.util.TimeUtil;
+import org.junit.Assert;
import org.junit.Test;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
+import java.util.Map;
import java.util.Random;
import java.util.concurrent.Callable;
+import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
@@ -198,4 +204,125 @@ private static void logNode(StatisticNode node) {
private static void log(Object obj) {
System.out.println(LOG_PREFIX + obj);
}
+
+
+ /**
+ * com.alibaba.csp.sentinel.node.StatisticNode#curThreadNum using LongAdder replace the AtomicInteger.
+ * now test the LongAdder is fast than AtomicInteger
+ * and get the right statistic or not
+ */
+ @Test
+ public void testStatisticLongAdder() throws InterruptedException {
+ AtomicInteger atomicInteger = new AtomicInteger(0);
+ StatisticNode statisticNode = new StatisticNode();
+ ExecutorService bizEs1 = new ThreadPoolExecutor(THREAD_COUNT, THREAD_COUNT,
+ 0L, TimeUnit.MILLISECONDS,
+ new LinkedBlockingQueue());
+ ExecutorService bizEs2 = new ThreadPoolExecutor(THREAD_COUNT, THREAD_COUNT,
+ 0L, TimeUnit.MILLISECONDS,
+ new LinkedBlockingQueue());
+ int taskCount = 100;
+ for (int i = 0; i < taskCount; i++) {
+ int op = i % 2;
+ bizEs2.submit(new StatisticAtomicIntegerTask(atomicInteger, op, i));
+ bizEs1.submit(new StatisticLongAdderTask(statisticNode, op, i));
+ }
+ Thread.sleep(5000);
+
+ log("LongAdder totalCost : " + StatisticLongAdderTask.totalCost() + "ms");
+ log("AtomicInteger totalCost : " + StatisticAtomicIntegerTask.totalCost() + "ms");
+ Assert.assertEquals(statisticNode.curThreadNum(), atomicInteger.get());
+
+
+ }
+
+ private static class StatisticLongAdderTask implements Runnable {
+
+
+ private StatisticNode statisticNode;
+ /**
+ * 0 addition
+ * 1 subtraction
+ */
+ private int op;
+
+ private int taskId;
+
+ private static Map taskCostMap = new ConcurrentHashMap<>(16);
+
+
+ public StatisticLongAdderTask(StatisticNode statisticNode, int op, int taskId) {
+ this.statisticNode = statisticNode;
+ this.op = op;
+ this.taskId = taskId;
+ }
+
+ @Override
+ public void run() {
+ long startTime = System.currentTimeMillis();
+ int calCount = 100000;
+ for (int i = 0; i < calCount; i++) {
+ if (op == 0) {
+ statisticNode.increaseThreadNum();
+ } else if (op == 1) {
+ statisticNode.decreaseThreadNum();
+ }
+ }
+ long cost = System.currentTimeMillis() - startTime;
+ taskCostMap.put(taskId, cost);
+ }
+
+ public static long totalCost() {
+ long totalCost = 0;
+ for (long cost : taskCostMap.values()) {
+ totalCost += cost;
+ }
+ return totalCost;
+ }
+ }
+
+ private static class StatisticAtomicIntegerTask implements Runnable {
+
+ AtomicInteger atomicInteger;
+ /**
+ * 0 addition
+ * 1 subtraction
+ */
+ private int op;
+
+ private int taskId;
+
+ private static Map taskCostMap = new ConcurrentHashMap<>(16);
+
+ public StatisticAtomicIntegerTask(AtomicInteger atomicInteger, int op, int taskId) {
+ this.atomicInteger = atomicInteger;
+ this.op = op;
+ this.taskId = taskId;
+ }
+
+ @Override
+ public void run() {
+ long startTime = System.currentTimeMillis();
+ int calCount = 100000;
+ for (int i = 0; i < calCount; i++) {
+ if (op == 0) {
+ atomicInteger.incrementAndGet();
+ } else if (op == 1) {
+ atomicInteger.decrementAndGet();
+ }
+ }
+ long cost = System.currentTimeMillis() - startTime;
+ taskCostMap.put(taskId, cost);
+ }
+
+ public static long totalCost() {
+ long totalCost = 0;
+ for (long cost : taskCostMap.values()) {
+ totalCost += cost;
+ }
+ return totalCost;
+ }
+ }
+
+
}
diff --git a/sentinel-core/src/test/java/com/alibaba/csp/sentinel/slots/block/flow/FlowRuleCheckerTest.java b/sentinel-core/src/test/java/com/alibaba/csp/sentinel/slots/block/flow/FlowRuleCheckerTest.java
index 10c460f383..bdd8072d47 100644
--- a/sentinel-core/src/test/java/com/alibaba/csp/sentinel/slots/block/flow/FlowRuleCheckerTest.java
+++ b/sentinel-core/src/test/java/com/alibaba/csp/sentinel/slots/block/flow/FlowRuleCheckerTest.java
@@ -149,7 +149,8 @@ public void testSelectReferenceNodeForContextEntrance() {
public void testPassCheckNullLimitApp() {
FlowRule rule = new FlowRule("abc").setCount(1);
rule.setLimitApp(null);
- assertTrue(FlowRuleChecker.passCheck(rule, null, null, 1));
+ FlowRuleChecker checker = new FlowRuleChecker();
+ assertTrue(checker.canPassCheck(rule, null, null, 1));
}
@Test
@@ -161,7 +162,8 @@ public void testPassCheckSelectEmptyNodeSuccess() {
Context context = mock(Context.class);
when(context.getOrigin()).thenReturn("def");
- assertTrue(FlowRuleChecker.passCheck(rule, context, node, 1));
+ FlowRuleChecker checker = new FlowRuleChecker();
+ assertTrue(checker.canPassCheck(rule, context, node, 1));
}
@Before
diff --git a/sentinel-core/src/test/java/com/alibaba/csp/sentinel/slots/block/flow/FlowSlotTest.java b/sentinel-core/src/test/java/com/alibaba/csp/sentinel/slots/block/flow/FlowSlotTest.java
index ee5de0a8b8..66026e2bb7 100644
--- a/sentinel-core/src/test/java/com/alibaba/csp/sentinel/slots/block/flow/FlowSlotTest.java
+++ b/sentinel-core/src/test/java/com/alibaba/csp/sentinel/slots/block/flow/FlowSlotTest.java
@@ -23,6 +23,7 @@
import com.alibaba.csp.sentinel.node.DefaultNode;
import com.alibaba.csp.sentinel.slotchain.ResourceWrapper;
import com.alibaba.csp.sentinel.slotchain.StringResourceWrapper;
+import com.alibaba.csp.sentinel.util.function.Function;
import org.junit.After;
import org.junit.Before;
@@ -49,11 +50,13 @@ public void tearDown() {
}
@Test
+ @SuppressWarnings("unchecked")
public void testCheckFlowPass() throws Exception {
- FlowSlot flowSlot = mock(FlowSlot.class);
+ FlowRuleChecker checker = mock(FlowRuleChecker.class);
+ FlowSlot flowSlot = new FlowSlot(checker);
Context context = mock(Context.class);
DefaultNode node = mock(DefaultNode.class);
- doCallRealMethod().when(flowSlot).checkFlow(any(ResourceWrapper.class), any(Context.class),
+ doCallRealMethod().when(checker).checkFlow(any(Function.class), any(ResourceWrapper.class), any(Context.class),
any(DefaultNode.class), anyInt(), anyBoolean());
String resA = "resAK";
@@ -63,9 +66,9 @@ public void testCheckFlowPass() throws Exception {
// Here we only load rules for resA.
FlowRuleManager.loadRules(Collections.singletonList(rule1));
- when(flowSlot.canPassCheck(eq(rule1), any(Context.class), any(DefaultNode.class), anyInt(), anyBoolean()))
+ when(checker.canPassCheck(eq(rule1), any(Context.class), any(DefaultNode.class), anyInt(), anyBoolean()))
.thenReturn(true);
- when(flowSlot.canPassCheck(eq(rule2), any(Context.class), any(DefaultNode.class), anyInt(), anyBoolean()))
+ when(checker.canPassCheck(eq(rule2), any(Context.class), any(DefaultNode.class), anyInt(), anyBoolean()))
.thenReturn(false);
flowSlot.checkFlow(new StringResourceWrapper(resA, EntryType.IN), context, node, 1, false);
@@ -73,20 +76,22 @@ public void testCheckFlowPass() throws Exception {
}
@Test(expected = FlowException.class)
+ @SuppressWarnings("unchecked")
public void testCheckFlowBlock() throws Exception {
- FlowSlot flowSlot = mock(FlowSlot.class);
+ FlowRuleChecker checker = mock(FlowRuleChecker.class);
+ FlowSlot flowSlot = new FlowSlot(checker);
Context context = mock(Context.class);
DefaultNode node = mock(DefaultNode.class);
- doCallRealMethod().when(flowSlot).checkFlow(any(ResourceWrapper.class), any(Context.class),
+ doCallRealMethod().when(checker).checkFlow(any(Function.class), any(ResourceWrapper.class), any(Context.class),
any(DefaultNode.class), anyInt(), anyBoolean());
String resA = "resAK";
FlowRule rule = new FlowRule(resA).setCount(10);
FlowRuleManager.loadRules(Collections.singletonList(rule));
- when(flowSlot.canPassCheck(any(FlowRule.class), any(Context.class), any(DefaultNode.class), anyInt(), anyBoolean()))
+ when(checker.canPassCheck(any(FlowRule.class), any(Context.class), any(DefaultNode.class), anyInt(), anyBoolean()))
.thenReturn(false);
flowSlot.checkFlow(new StringResourceWrapper(resA, EntryType.IN), context, node, 1, false);
}
-}
\ No newline at end of file
+}
diff --git a/sentinel-dashboard/pom.xml b/sentinel-dashboard/pom.xml
index 4f7a9bc8dc..b8bafb1090 100755
--- a/sentinel-dashboard/pom.xml
+++ b/sentinel-dashboard/pom.xml
@@ -6,7 +6,7 @@
com.alibaba.csp
sentinel-parent
- 1.6.0-SNAPSHOT
+ 1.7.0-SNAPSHOT
sentinel-dashboard
@@ -16,6 +16,7 @@
1.8
1.8
2.0.5.RELEASE
+ 4.0.1
@@ -106,6 +107,14 @@
test