Browse Source

Refactor FlowRuleChecker to improve code reuse

Signed-off-by: Eric Zhao <sczyh16@gmail.com>
master
Eric Zhao 5 years ago
parent
commit
54da16d304
4 changed files with 78 additions and 35 deletions
  1. +29
    -9
      sentinel-core/src/main/java/com/alibaba/csp/sentinel/slots/block/flow/FlowRuleChecker.java
  2. +32
    -16
      sentinel-core/src/main/java/com/alibaba/csp/sentinel/slots/block/flow/FlowSlot.java
  3. +4
    -2
      sentinel-core/src/test/java/com/alibaba/csp/sentinel/slots/block/flow/FlowRuleCheckerTest.java
  4. +13
    -8
      sentinel-core/src/test/java/com/alibaba/csp/sentinel/slots/block/flow/FlowSlotTest.java

+ 29
- 9
sentinel-core/src/main/java/com/alibaba/csp/sentinel/slots/block/flow/FlowRuleChecker.java View File

@@ -15,6 +15,8 @@
*/ */
package com.alibaba.csp.sentinel.slots.block.flow; package com.alibaba.csp.sentinel.slots.block.flow;


import java.util.Collection;

import com.alibaba.csp.sentinel.cluster.ClusterStateManager; import com.alibaba.csp.sentinel.cluster.ClusterStateManager;
import com.alibaba.csp.sentinel.cluster.server.EmbeddedClusterTokenServerProvider; import com.alibaba.csp.sentinel.cluster.server.EmbeddedClusterTokenServerProvider;
import com.alibaba.csp.sentinel.cluster.client.TokenClientProvider; import com.alibaba.csp.sentinel.cluster.client.TokenClientProvider;
@@ -25,23 +27,42 @@ import com.alibaba.csp.sentinel.context.Context;
import com.alibaba.csp.sentinel.log.RecordLog; import com.alibaba.csp.sentinel.log.RecordLog;
import com.alibaba.csp.sentinel.node.DefaultNode; import com.alibaba.csp.sentinel.node.DefaultNode;
import com.alibaba.csp.sentinel.node.Node; import com.alibaba.csp.sentinel.node.Node;
import com.alibaba.csp.sentinel.slotchain.ResourceWrapper;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.alibaba.csp.sentinel.slots.block.RuleConstant; import com.alibaba.csp.sentinel.slots.block.RuleConstant;
import com.alibaba.csp.sentinel.slots.clusterbuilder.ClusterBuilderSlot; import com.alibaba.csp.sentinel.slots.clusterbuilder.ClusterBuilderSlot;
import com.alibaba.csp.sentinel.util.StringUtil; import com.alibaba.csp.sentinel.util.StringUtil;
import com.alibaba.csp.sentinel.util.function.Function;


/** /**
* Rule checker for flow control rules. * Rule checker for flow control rules.
* *
* @author Eric Zhao * @author Eric Zhao
*/ */
final class FlowRuleChecker {
public class FlowRuleChecker {


static boolean passCheck(/*@NonNull*/ FlowRule rule, Context context, DefaultNode node, int acquireCount) {
return passCheck(rule, context, node, acquireCount, false);
public void checkFlow(Function<String, Collection<FlowRule>> ruleProvider, ResourceWrapper resource,
Context context, DefaultNode node, int count, boolean prioritized) throws BlockException {
if (ruleProvider == null || resource == null) {
return;
}
Collection<FlowRule> 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(); String limitApp = rule.getLimitApp();
if (limitApp == null) { if (limitApp == null) {
return true; return true;
@@ -162,8 +183,9 @@ final class FlowRuleChecker {
return null; 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()) { switch (result.getStatus()) {
case TokenResultStatus.OK: case TokenResultStatus.OK:
return true; return true;
@@ -185,6 +207,4 @@ final class FlowRuleChecker {
return false; return false;
} }
} }

private FlowRuleChecker() {}
} }

+ 32
- 16
sentinel-core/src/main/java/com/alibaba/csp/sentinel/slots/block/flow/FlowSlot.java View File

@@ -15,6 +15,7 @@
*/ */
package com.alibaba.csp.sentinel.slots.block.flow; package com.alibaba.csp.sentinel.slots.block.flow;


import java.util.Collection;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;


@@ -23,6 +24,8 @@ import com.alibaba.csp.sentinel.node.DefaultNode;
import com.alibaba.csp.sentinel.slotchain.AbstractLinkedProcessorSlot; import com.alibaba.csp.sentinel.slotchain.AbstractLinkedProcessorSlot;
import com.alibaba.csp.sentinel.slotchain.ResourceWrapper; import com.alibaba.csp.sentinel.slotchain.ResourceWrapper;
import com.alibaba.csp.sentinel.slots.block.BlockException; import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.alibaba.csp.sentinel.util.AssertUtil;
import com.alibaba.csp.sentinel.util.function.Function;


/** /**
* <p> * <p>
@@ -135,6 +138,23 @@ import com.alibaba.csp.sentinel.slots.block.BlockException;
*/ */
public class FlowSlot extends AbstractLinkedProcessorSlot<DefaultNode> { public class FlowSlot extends AbstractLinkedProcessorSlot<DefaultNode> {


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 @Override
public void entry(Context context, ResourceWrapper resourceWrapper, DefaultNode node, int count, public void entry(Context context, ResourceWrapper resourceWrapper, DefaultNode node, int count,
boolean prioritized, Object... args) throws Throwable { boolean prioritized, Object... args) throws Throwable {
@@ -143,26 +163,22 @@ public class FlowSlot extends AbstractLinkedProcessorSlot<DefaultNode> {
fireEntry(context, resourceWrapper, node, count, prioritized, args); 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<String, List<FlowRule>> flowRules = FlowRuleManager.getFlowRuleMap();

List<FlowRule> 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 @Override
public void exit(Context context, ResourceWrapper resourceWrapper, int count, Object... args) { public void exit(Context context, ResourceWrapper resourceWrapper, int count, Object... args) {
fireExit(context, resourceWrapper, count, args); fireExit(context, resourceWrapper, count, args);
} }

private final Function<String, Collection<FlowRule>> ruleProvider = new Function<String, Collection<FlowRule>>() {
@Override
public Collection<FlowRule> apply(String resource) {
// Flow rule map should not be null.
Map<String, List<FlowRule>> flowRules = FlowRuleManager.getFlowRuleMap();
return flowRules.get(resource);
}
};
} }

+ 4
- 2
sentinel-core/src/test/java/com/alibaba/csp/sentinel/slots/block/flow/FlowRuleCheckerTest.java View File

@@ -149,7 +149,8 @@ public class FlowRuleCheckerTest {
public void testPassCheckNullLimitApp() { public void testPassCheckNullLimitApp() {
FlowRule rule = new FlowRule("abc").setCount(1); FlowRule rule = new FlowRule("abc").setCount(1);
rule.setLimitApp(null); rule.setLimitApp(null);
assertTrue(FlowRuleChecker.passCheck(rule, null, null, 1));
FlowRuleChecker checker = new FlowRuleChecker();
assertTrue(checker.canPassCheck(rule, null, null, 1));
} }


@Test @Test
@@ -161,7 +162,8 @@ public class FlowRuleCheckerTest {
Context context = mock(Context.class); Context context = mock(Context.class);
when(context.getOrigin()).thenReturn("def"); when(context.getOrigin()).thenReturn("def");


assertTrue(FlowRuleChecker.passCheck(rule, context, node, 1));
FlowRuleChecker checker = new FlowRuleChecker();
assertTrue(checker.canPassCheck(rule, context, node, 1));
} }


@Before @Before


+ 13
- 8
sentinel-core/src/test/java/com/alibaba/csp/sentinel/slots/block/flow/FlowSlotTest.java View File

@@ -23,6 +23,7 @@ import com.alibaba.csp.sentinel.context.ContextTestUtil;
import com.alibaba.csp.sentinel.node.DefaultNode; import com.alibaba.csp.sentinel.node.DefaultNode;
import com.alibaba.csp.sentinel.slotchain.ResourceWrapper; import com.alibaba.csp.sentinel.slotchain.ResourceWrapper;
import com.alibaba.csp.sentinel.slotchain.StringResourceWrapper; import com.alibaba.csp.sentinel.slotchain.StringResourceWrapper;
import com.alibaba.csp.sentinel.util.function.Function;


import org.junit.After; import org.junit.After;
import org.junit.Before; import org.junit.Before;
@@ -49,11 +50,13 @@ public class FlowSlotTest {
} }


@Test @Test
@SuppressWarnings("unchecked")
public void testCheckFlowPass() throws Exception { 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); Context context = mock(Context.class);
DefaultNode node = mock(DefaultNode.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()); any(DefaultNode.class), anyInt(), anyBoolean());


String resA = "resAK"; String resA = "resAK";
@@ -63,9 +66,9 @@ public class FlowSlotTest {
// Here we only load rules for resA. // Here we only load rules for resA.
FlowRuleManager.loadRules(Collections.singletonList(rule1)); 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); .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); .thenReturn(false);


flowSlot.checkFlow(new StringResourceWrapper(resA, EntryType.IN), context, node, 1, false); flowSlot.checkFlow(new StringResourceWrapper(resA, EntryType.IN), context, node, 1, false);
@@ -73,20 +76,22 @@ public class FlowSlotTest {
} }


@Test(expected = FlowException.class) @Test(expected = FlowException.class)
@SuppressWarnings("unchecked")
public void testCheckFlowBlock() throws Exception { 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); Context context = mock(Context.class);
DefaultNode node = mock(DefaultNode.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()); any(DefaultNode.class), anyInt(), anyBoolean());


String resA = "resAK"; String resA = "resAK";
FlowRule rule = new FlowRule(resA).setCount(10); FlowRule rule = new FlowRule(resA).setCount(10);
FlowRuleManager.loadRules(Collections.singletonList(rule)); 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); .thenReturn(false);


flowSlot.checkFlow(new StringResourceWrapper(resA, EntryType.IN), context, node, 1, false); flowSlot.checkFlow(new StringResourceWrapper(resA, EntryType.IN), context, node, 1, false);
} }
}
}

Loading…
Cancel
Save