@@ -16,6 +16,7 @@ | |||||
package com.alibaba.csp.sentinel.node; | package com.alibaba.csp.sentinel.node; | ||||
import java.util.HashMap; | import java.util.HashMap; | ||||
import java.util.Map; | |||||
import java.util.concurrent.locks.ReentrantLock; | import java.util.concurrent.locks.ReentrantLock; | ||||
import com.alibaba.csp.sentinel.context.ContextUtil; | import com.alibaba.csp.sentinel.context.ContextUtil; | ||||
@@ -31,7 +32,7 @@ import com.alibaba.csp.sentinel.slots.block.BlockException; | |||||
* To distinguish invocation from different origin (declared in | * To distinguish invocation from different origin (declared in | ||||
* {@link ContextUtil#enter(String name, String origin)}), | * {@link ContextUtil#enter(String name, String origin)}), | ||||
* one {@link ClusterNode} holds an {@link #originCountMap}, this map holds {@link StatisticNode} | * one {@link ClusterNode} holds an {@link #originCountMap}, this map holds {@link StatisticNode} | ||||
* of different origin. Use {@link #getOriginNode(String)} to get {@link Node} of the specific | |||||
* of different origin. Use {@link #getOrCreateOriginNode(String)} to get {@link Node} of the specific | |||||
* origin.<br/> | * origin.<br/> | ||||
* Note that 'origin' usually is Service Consumer's app name. | * Note that 'origin' usually is Service Consumer's app name. | ||||
* </p> | * </p> | ||||
@@ -42,30 +43,31 @@ import com.alibaba.csp.sentinel.slots.block.BlockException; | |||||
public class ClusterNode extends StatisticNode { | public class ClusterNode extends StatisticNode { | ||||
/** | /** | ||||
* <p> | |||||
* the longer the application runs, the more stable this mapping will | |||||
* The longer the application runs, the more stable this mapping will | |||||
* become. so we don't concurrent map but a lock. as this lock only happens | * become. so we don't concurrent map but a lock. as this lock only happens | ||||
* at the very beginning while concurrent map will hold the lock all the | |||||
* time | |||||
* </p> | |||||
* at the very beginning while concurrent map will hold the lock all the time. | |||||
*/ | */ | ||||
private HashMap<String, StatisticNode> originCountMap = new HashMap<String, StatisticNode>(); | |||||
private ReentrantLock lock = new ReentrantLock(); | |||||
private Map<String, StatisticNode> originCountMap = new HashMap<String, StatisticNode>(); | |||||
private final ReentrantLock lock = new ReentrantLock(); | |||||
/** | /** | ||||
* Get {@link Node} of the specific origin. Usually the origin is the Service Consumer's app name. | |||||
* <p>Get {@link Node} of the specific origin. Usually the origin is the Service Consumer's app name.</p> | |||||
* <p>If the origin node for given origin is absent, then a new {@link StatisticNode} | |||||
* for the origin will be created and returned.</p> | |||||
* | * | ||||
* @param origin The caller's name. It is declared in the | |||||
* @param origin The caller's name, which is designated in the {@code parameter} parameter | |||||
* {@link ContextUtil#enter(String name, String origin)}. | * {@link ContextUtil#enter(String name, String origin)}. | ||||
* @return the {@link Node} of the specific origin. | |||||
* @return the {@link Node} of the specific origin | |||||
*/ | */ | ||||
public Node getOriginNode(String origin) { | |||||
public Node getOrCreateOriginNode(String origin) { | |||||
StatisticNode statisticNode = originCountMap.get(origin); | StatisticNode statisticNode = originCountMap.get(origin); | ||||
if (statisticNode == null) { | if (statisticNode == null) { | ||||
try { | try { | ||||
lock.lock(); | lock.lock(); | ||||
statisticNode = originCountMap.get(origin); | statisticNode = originCountMap.get(origin); | ||||
if (statisticNode == null) { | if (statisticNode == null) { | ||||
// The node is absent, create a new node for the origin. | |||||
statisticNode = new StatisticNode(); | statisticNode = new StatisticNode(); | ||||
HashMap<String, StatisticNode> newMap = new HashMap<String, StatisticNode>( | HashMap<String, StatisticNode> newMap = new HashMap<String, StatisticNode>( | ||||
originCountMap.size() + 1); | originCountMap.size() + 1); | ||||
@@ -80,15 +82,15 @@ public class ClusterNode extends StatisticNode { | |||||
return statisticNode; | return statisticNode; | ||||
} | } | ||||
public synchronized HashMap<String, StatisticNode> getOriginCountMap() { | |||||
public synchronized Map<String, StatisticNode> getOriginCountMap() { | |||||
return originCountMap; | return originCountMap; | ||||
} | } | ||||
/** | /** | ||||
* Add exception count only when {@code throwable} is not {@link BlockException#isBlockException(Throwable)} | |||||
* Add exception count only when given {@code throwable} is not a {@link BlockException}. | |||||
* | * | ||||
* @param throwable | |||||
* @param count count to add. | |||||
* @param throwable target exception | |||||
* @param count count to add | |||||
*/ | */ | ||||
public void trace(Throwable throwable, int count) { | public void trace(Throwable throwable, int count) { | ||||
if (!BlockException.isBlockException(throwable)) { | if (!BlockException.isBlockException(throwable)) { | ||||
@@ -40,10 +40,19 @@ import com.alibaba.csp.sentinel.slots.nodeselector.NodeSelectorSlot; | |||||
*/ | */ | ||||
public class DefaultNode extends StatisticNode { | public class DefaultNode extends StatisticNode { | ||||
/** | |||||
* The resource associated with the node. | |||||
*/ | |||||
private ResourceWrapper id; | private ResourceWrapper id; | ||||
private volatile HashSet<Node> childList = new HashSet<Node>(); | |||||
/** | |||||
* The list of all child nodes. | |||||
*/ | |||||
private volatile Set<Node> childList = new HashSet<Node>(); | |||||
/** | |||||
* Associated cluster node. | |||||
*/ | |||||
private ClusterNode clusterNode; | private ClusterNode clusterNode; | ||||
public DefaultNode(ResourceWrapper id, ClusterNode clusterNode) { | public DefaultNode(ResourceWrapper id, ClusterNode clusterNode) { | ||||
@@ -63,22 +72,32 @@ public class DefaultNode extends StatisticNode { | |||||
this.clusterNode = clusterNode; | this.clusterNode = clusterNode; | ||||
} | } | ||||
/** | |||||
* Add child node to current node. | |||||
* | |||||
* @param node valid child node | |||||
*/ | |||||
public void addChild(Node node) { | public void addChild(Node node) { | ||||
if (node == null) { | |||||
RecordLog.warn("Trying to add null child to node <{0}>, ignored", id.getName()); | |||||
return; | |||||
} | |||||
if (!childList.contains(node)) { | if (!childList.contains(node)) { | ||||
synchronized (this) { | synchronized (this) { | ||||
if (!childList.contains(node)) { | if (!childList.contains(node)) { | ||||
HashSet<Node> newSet = new HashSet<Node>(childList.size() + 1); | |||||
Set<Node> newSet = new HashSet<Node>(childList.size() + 1); | |||||
newSet.addAll(childList); | newSet.addAll(childList); | ||||
newSet.add(node); | newSet.add(node); | ||||
childList = newSet; | childList = newSet; | ||||
} | } | ||||
} | } | ||||
RecordLog.info(String.format("Add child %s to %s", ((DefaultNode)node).id.getName(), id.getName())); | |||||
RecordLog.info("Add child <{0}> to node <{1}>", ((DefaultNode)node).id.getName(), id.getName()); | |||||
} | } | ||||
} | } | ||||
/** | |||||
* Reset the child node list. | |||||
*/ | |||||
public void removeChildList() { | public void removeChildList() { | ||||
this.childList = new HashSet<Node>(); | this.childList = new HashSet<Node>(); | ||||
} | } | ||||
@@ -18,6 +18,8 @@ package com.alibaba.csp.sentinel.node; | |||||
import com.alibaba.csp.sentinel.slotchain.ResourceWrapper; | import com.alibaba.csp.sentinel.slotchain.ResourceWrapper; | ||||
/** | /** | ||||
* Default implementation of {@link NodeBuilder}. | |||||
* | |||||
* @author qinan.qn | * @author qinan.qn | ||||
*/ | */ | ||||
public class DefaultNodeBuilder implements NodeBuilder { | public class DefaultNodeBuilder implements NodeBuilder { | ||||
@@ -25,6 +25,7 @@ import com.alibaba.csp.sentinel.node.metric.MetricNode; | |||||
* | * | ||||
* @author qinan.qn | * @author qinan.qn | ||||
* @author leyou | * @author leyou | ||||
* @author Eric Zhao | |||||
*/ | */ | ||||
public interface Node { | public interface Node { | ||||
@@ -70,6 +71,11 @@ public interface Node { | |||||
*/ | */ | ||||
long successQps(); | long successQps(); | ||||
/** | |||||
* Get estimated max success QPS till now. | |||||
* | |||||
* @return max success QPS | |||||
*/ | |||||
long maxSuccessQps(); | long maxSuccessQps(); | ||||
/** | /** | ||||
@@ -79,9 +85,16 @@ public interface Node { | |||||
/** | /** | ||||
* Get average rt per second. | * Get average rt per second. | ||||
* | |||||
* @return average response time per second | |||||
*/ | */ | ||||
long avgRt(); | long avgRt(); | ||||
/** | |||||
* Get minimal response time. | |||||
* | |||||
* @return recorded minimal response time | |||||
*/ | |||||
long minRt(); | long minRt(); | ||||
/** | /** | ||||
@@ -99,23 +112,43 @@ public interface Node { | |||||
*/ | */ | ||||
long previousPassQps(); | long previousPassQps(); | ||||
/** | |||||
* Fetch all valid metric nodes of resources. | |||||
* | |||||
* @return valid metric nodes of resources | |||||
*/ | |||||
Map<Long, MetricNode> metrics(); | Map<Long, MetricNode> metrics(); | ||||
/** | |||||
* Add pass count. | |||||
*/ | |||||
void addPassRequest(); | void addPassRequest(); | ||||
/** | /** | ||||
* Add rt and success count. | * Add rt and success count. | ||||
* | * | ||||
* @param rt | |||||
* @param rt response time | |||||
*/ | */ | ||||
void rt(long rt); | void rt(long rt); | ||||
/** | |||||
* Increase the block count. | |||||
*/ | |||||
void increaseBlockQps(); | void increaseBlockQps(); | ||||
/** | |||||
* Increase the biz exception count. | |||||
*/ | |||||
void increaseExceptionQps(); | void increaseExceptionQps(); | ||||
/** | |||||
* Increase current thread count. | |||||
*/ | |||||
void increaseThreadNum(); | void increaseThreadNum(); | ||||
/** | |||||
* Increase current thread count. | |||||
*/ | |||||
void decreaseThreadNum(); | void decreaseThreadNum(); | ||||
/** | /** | ||||
@@ -24,7 +24,19 @@ import com.alibaba.csp.sentinel.slotchain.ResourceWrapper; | |||||
*/ | */ | ||||
public interface NodeBuilder { | public interface NodeBuilder { | ||||
/** | |||||
* Create a new {@link DefaultNode} as tree node. | |||||
* | |||||
* @param id resource | |||||
* @param clusterNode the cluster node of the provided resource | |||||
* @return new created tree node | |||||
*/ | |||||
DefaultNode buildTreeNode(ResourceWrapper id, ClusterNode clusterNode); | DefaultNode buildTreeNode(ResourceWrapper id, ClusterNode clusterNode); | ||||
/** | |||||
* Create a new {@link ClusterNode} as universal statistic node for a single resource. | |||||
* | |||||
* @return new created cluster node | |||||
*/ | |||||
ClusterNode buildClusterNode(); | ClusterNode buildClusterNode(); | ||||
} | } |
@@ -106,25 +106,24 @@ public class StatisticNode implements Node { | |||||
*/ | */ | ||||
private AtomicInteger curThreadNum = new AtomicInteger(0); | private AtomicInteger curThreadNum = new AtomicInteger(0); | ||||
/** | |||||
* The last timestamp when metrics were fetched. | |||||
*/ | |||||
private long lastFetchTime = -1; | private long lastFetchTime = -1; | ||||
@Override | @Override | ||||
public Map<Long, MetricNode> metrics() { | public Map<Long, MetricNode> metrics() { | ||||
// The fetch operation is thread-safe under a single-thread scheduler pool. | |||||
long currentTime = TimeUtil.currentTimeMillis(); | long currentTime = TimeUtil.currentTimeMillis(); | ||||
currentTime = currentTime - currentTime % 1000; | currentTime = currentTime - currentTime % 1000; | ||||
Map<Long, MetricNode> metrics = new ConcurrentHashMap<Long, MetricNode>(); | Map<Long, MetricNode> metrics = new ConcurrentHashMap<Long, MetricNode>(); | ||||
List<MetricNode> nodesOfEverySecond = rollingCounterInMinute.details(); | List<MetricNode> nodesOfEverySecond = rollingCounterInMinute.details(); | ||||
long newLastFetchTime = lastFetchTime; | long newLastFetchTime = lastFetchTime; | ||||
// Iterate metrics of all resources, filter valid metrics (not-empty and up-to-date). | |||||
for (MetricNode node : nodesOfEverySecond) { | for (MetricNode node : nodesOfEverySecond) { | ||||
if (node.getTimestamp() > lastFetchTime && node.getTimestamp() < currentTime) { | |||||
if (node.getPassQps() != 0 | |||||
|| node.getBlockQps() != 0 | |||||
|| node.getSuccessQps() != 0 | |||||
|| node.getExceptionQps() != 0 | |||||
|| node.getRt() != 0) { | |||||
metrics.put(node.getTimestamp(), node); | |||||
newLastFetchTime = Math.max(newLastFetchTime, node.getTimestamp()); | |||||
} | |||||
if (isNodeInTime(node, currentTime) && isValidMetricNode(node)) { | |||||
metrics.put(node.getTimestamp(), node); | |||||
newLastFetchTime = Math.max(newLastFetchTime, node.getTimestamp()); | |||||
} | } | ||||
} | } | ||||
lastFetchTime = newLastFetchTime; | lastFetchTime = newLastFetchTime; | ||||
@@ -132,6 +131,15 @@ public class StatisticNode implements Node { | |||||
return metrics; | return metrics; | ||||
} | } | ||||
private boolean isNodeInTime(MetricNode node, long currentTime) { | |||||
return node.getTimestamp() > lastFetchTime && node.getTimestamp() < currentTime; | |||||
} | |||||
private boolean isValidMetricNode(MetricNode node) { | |||||
return node.getPassQps() > 0 || node.getBlockQps() > 0 || node.getSuccessQps() > 0 | |||||
|| node.getExceptionQps() > 0 || node.getRt() > 0; | |||||
} | |||||
@Override | @Override | ||||
public void reset() { | public void reset() { | ||||
rollingCounterInSecond = new ArrayMetric(1000 / SampleCountProperty.SAMPLE_COUNT, IntervalProperty.INTERVAL); | rollingCounterInSecond = new ArrayMetric(1000 / SampleCountProperty.SAMPLE_COUNT, IntervalProperty.INTERVAL); | ||||
@@ -19,6 +19,12 @@ import java.text.DateFormat; | |||||
import java.text.SimpleDateFormat; | import java.text.SimpleDateFormat; | ||||
import java.util.Date; | import java.util.Date; | ||||
/** | |||||
* Metrics data for a specific resource at given {@code timestamp}. | |||||
* | |||||
* @author jialiang.linjl | |||||
* @author Carpenter Lee | |||||
*/ | |||||
public class MetricNode { | public class MetricNode { | ||||
private long timestamp; | private long timestamp; | ||||
@@ -27,6 +27,9 @@ import com.alibaba.csp.sentinel.node.ClusterNode; | |||||
import com.alibaba.csp.sentinel.slotchain.ResourceWrapper; | import com.alibaba.csp.sentinel.slotchain.ResourceWrapper; | ||||
import com.alibaba.csp.sentinel.slots.clusterbuilder.ClusterBuilderSlot; | import com.alibaba.csp.sentinel.slots.clusterbuilder.ClusterBuilderSlot; | ||||
/** | |||||
* @author jialiang.linjl | |||||
*/ | |||||
public class MetricTimerListener implements Runnable { | public class MetricTimerListener implements Runnable { | ||||
private static final MetricWriter metricWriter = new MetricWriter(SentinelConfig.singleMetricFileSize(), | private static final MetricWriter metricWriter = new MetricWriter(SentinelConfig.singleMetricFileSize(), | ||||
@@ -57,11 +60,10 @@ public class MetricTimerListener implements Runnable { | |||||
try { | try { | ||||
metricWriter.write(entry.getKey(), entry.getValue()); | metricWriter.write(entry.getKey(), entry.getValue()); | ||||
} catch (Exception e) { | } catch (Exception e) { | ||||
RecordLog.info("write metric error: ", e); | |||||
RecordLog.warn("[MetricTimerListener] Write metric error", e); | |||||
} | } | ||||
} | } | ||||
} | } | ||||
} | } | ||||
} | } |
@@ -22,12 +22,17 @@ import java.nio.charset.Charset; | |||||
import java.util.ArrayList; | import java.util.ArrayList; | ||||
import java.util.List; | import java.util.List; | ||||
/** | |||||
* Reads metrics data from log file. | |||||
*/ | |||||
class MetricsReader { | class MetricsReader { | ||||
/** | /** | ||||
* avoid OOM in any case | |||||
* Avoid OOM in any cases. | |||||
*/ | */ | ||||
private static final int maxLinesReturn = 100000; | |||||
private Charset charset; | |||||
private static final int MAX_LINES_RETURN = 100000; | |||||
private final Charset charset; | |||||
public MetricsReader(Charset charset) { | public MetricsReader(Charset charset) { | ||||
this.charset = charset; | this.charset = charset; | ||||
@@ -58,7 +63,7 @@ class MetricsReader { | |||||
} else { | } else { | ||||
return false; | return false; | ||||
} | } | ||||
if (list.size() >= maxLinesReturn) { | |||||
if (list.size() >= MAX_LINES_RETURN) { | |||||
return false; | return false; | ||||
} | } | ||||
} | } | ||||
@@ -28,7 +28,7 @@ import com.alibaba.csp.sentinel.slots.statistic.StatisticSlot; | |||||
import com.alibaba.csp.sentinel.slots.system.SystemSlot; | import com.alibaba.csp.sentinel.slots.system.SystemSlot; | ||||
/** | /** | ||||
* Helper class to create {@link ProcessorSlotChain}. | |||||
* Builder for a default {@link ProcessorSlotChain}. | |||||
* | * | ||||
* @author qinan.qn | * @author qinan.qn | ||||
* @author leyou | * @author leyou | ||||
@@ -29,6 +29,7 @@ public class RateLimiterController implements TrafficShapingController { | |||||
private final int maxQueueingTimeMs; | private final int maxQueueingTimeMs; | ||||
private final double count; | private final double count; | ||||
private final AtomicLong latestPassedTime = new AtomicLong(-1); | private final AtomicLong latestPassedTime = new AtomicLong(-1); | ||||
public RateLimiterController(int timeOut, double count) { | public RateLimiterController(int timeOut, double count) { | ||||
@@ -38,21 +39,19 @@ public class RateLimiterController implements TrafficShapingController { | |||||
@Override | @Override | ||||
public boolean canPass(Node node, int acquireCount) { | public boolean canPass(Node node, int acquireCount) { | ||||
// 按照斜率来计算计划中应该什么时候通过 | |||||
long currentTime = TimeUtil.currentTimeMillis(); | long currentTime = TimeUtil.currentTimeMillis(); | ||||
// Calculate the interval between every two requests. | |||||
long costTime = Math.round(1.0 * (acquireCount) / count * 1000); | long costTime = Math.round(1.0 * (acquireCount) / count * 1000); | ||||
//期待时间 | |||||
// Expected pass time of this request. | |||||
long expectedTime = costTime + latestPassedTime.get(); | long expectedTime = costTime + latestPassedTime.get(); | ||||
if (expectedTime <= currentTime) { | if (expectedTime <= currentTime) { | ||||
//这里会有冲突,然而冲突就冲突吧. | |||||
// Contention may exist here, but it's okay. | |||||
latestPassedTime.set(currentTime); | latestPassedTime.set(currentTime); | ||||
return true; | return true; | ||||
} else { | } else { | ||||
// 计算自己需要的等待时间 | |||||
// Calculate the time to wait. | |||||
long waitTime = costTime + latestPassedTime.get() - TimeUtil.currentTimeMillis(); | long waitTime = costTime + latestPassedTime.get() - TimeUtil.currentTimeMillis(); | ||||
if (waitTime >= maxQueueingTimeMs) { | if (waitTime >= maxQueueingTimeMs) { | ||||
return false; | return false; | ||||
@@ -70,7 +69,6 @@ public class RateLimiterController implements TrafficShapingController { | |||||
} | } | ||||
} | } | ||||
} | } | ||||
return false; | return false; | ||||
} | } | ||||
@@ -51,7 +51,7 @@ public class ClusterBuilderSlot extends AbstractLinkedProcessorSlot<DefaultNode> | |||||
* <p> | * <p> | ||||
* Remember that same resource({@link ResourceWrapper#equals(Object)}) will share | * Remember that same resource({@link ResourceWrapper#equals(Object)}) will share | ||||
* the same {@link ProcessorSlotChain} globally, no matter in witch context. So if | * the same {@link ProcessorSlotChain} globally, no matter in witch context. So if | ||||
* code goes into {@link #entry(Context, ResourceWrapper, DefaultNode, int, Object...)}, | |||||
* code goes into {@link #entry(Context, ResourceWrapper, DefaultNode, int, boolean, Object...)}, | |||||
* the resource name must be same but context name may not. | * the resource name must be same but context name may not. | ||||
* </p> | * </p> | ||||
* <p> | * <p> | ||||
@@ -62,8 +62,7 @@ public class ClusterBuilderSlot extends AbstractLinkedProcessorSlot<DefaultNode> | |||||
* <p> | * <p> | ||||
* The longer the application runs, the more stable this mapping will | * The longer the application runs, the more stable this mapping will | ||||
* become. so we don't concurrent map but a lock. as this lock only happens | * become. so we don't concurrent map but a lock. as this lock only happens | ||||
* at the very beginning while concurrent map will hold the lock all the | |||||
* time | |||||
* at the very beginning while concurrent map will hold the lock all the time. | |||||
* </p> | * </p> | ||||
*/ | */ | ||||
private static volatile Map<ResourceWrapper, ClusterNode> clusterNodeMap | private static volatile Map<ResourceWrapper, ClusterNode> clusterNodeMap | ||||
@@ -74,7 +73,8 @@ public class ClusterBuilderSlot extends AbstractLinkedProcessorSlot<DefaultNode> | |||||
private ClusterNode clusterNode = null; | private ClusterNode clusterNode = null; | ||||
@Override | @Override | ||||
public void entry(Context context, ResourceWrapper resourceWrapper, DefaultNode node, int count, boolean prioritized, Object... args) | |||||
public void entry(Context context, ResourceWrapper resourceWrapper, DefaultNode node, int count, | |||||
boolean prioritized, Object... args) | |||||
throws Throwable { | throws Throwable { | ||||
if (clusterNode == null) { | if (clusterNode == null) { | ||||
synchronized (lock) { | synchronized (lock) { | ||||
@@ -96,7 +96,7 @@ public class ClusterBuilderSlot extends AbstractLinkedProcessorSlot<DefaultNode> | |||||
* the specific origin. | * the specific origin. | ||||
*/ | */ | ||||
if (!"".equals(context.getOrigin())) { | if (!"".equals(context.getOrigin())) { | ||||
Node originNode = node.getClusterNode().getOriginNode(context.getOrigin()); | |||||
Node originNode = node.getClusterNode().getOrCreateOriginNode(context.getOrigin()); | |||||
context.getCurEntry().setOriginNode(originNode); | context.getCurEntry().setOriginNode(originNode); | ||||
} | } | ||||
@@ -45,6 +45,9 @@ public abstract class LeapArray<T> { | |||||
protected final AtomicReferenceArray<WindowWrap<T>> array; | protected final AtomicReferenceArray<WindowWrap<T>> array; | ||||
/** | |||||
* The fine-grained update lock is used only when current bucket is deprecated. | |||||
*/ | |||||
private final ReentrantLock updateLock = new ReentrantLock(); | private final ReentrantLock updateLock = new ReentrantLock(); | ||||
/** | /** | ||||
@@ -15,6 +15,8 @@ | |||||
*/ | */ | ||||
package com.alibaba.csp.sentinel.slots.clusterbuilder; | package com.alibaba.csp.sentinel.slots.clusterbuilder; | ||||
import static org.junit.Assert.assertNotSame; | |||||
import static org.junit.Assert.assertSame; | |||||
import static org.junit.Assert.assertTrue; | import static org.junit.Assert.assertTrue; | ||||
import org.junit.Test; | import org.junit.Test; | ||||
@@ -28,7 +30,7 @@ import com.alibaba.csp.sentinel.node.Node; | |||||
/** | /** | ||||
* @author jialiang.linjl | * @author jialiang.linjl | ||||
*/ | */ | ||||
public class ClusterNodeBuilder { | |||||
public class ClusterNodeBuilderTest { | |||||
@Test | @Test | ||||
public void clusterNodeBuilder_normal() throws Exception { | public void clusterNodeBuilder_normal() throws Exception { | ||||
@@ -37,10 +39,10 @@ public class ClusterNodeBuilder { | |||||
Entry nodeA = SphU.entry("nodeA"); | Entry nodeA = SphU.entry("nodeA"); | ||||
Node curNode = nodeA.getCurNode(); | Node curNode = nodeA.getCurNode(); | ||||
assertTrue(curNode.getClass() == DefaultNode.class); | |||||
assertSame(curNode.getClass(), DefaultNode.class); | |||||
DefaultNode dN = (DefaultNode)curNode; | DefaultNode dN = (DefaultNode)curNode; | ||||
assertTrue(dN.getClusterNode().getOriginCountMap().containsKey("caller1")); | assertTrue(dN.getClusterNode().getOriginCountMap().containsKey("caller1")); | ||||
assertTrue(nodeA.getOriginNode() == dN.getClusterNode().getOriginNode("caller1")); | |||||
assertSame(nodeA.getOriginNode(), dN.getClusterNode().getOrCreateOriginNode("caller1")); | |||||
if (nodeA != null) { | if (nodeA != null) { | ||||
nodeA.exit(); | nodeA.exit(); | ||||
@@ -52,10 +54,10 @@ public class ClusterNodeBuilder { | |||||
nodeA = SphU.entry("nodeA"); | nodeA = SphU.entry("nodeA"); | ||||
curNode = nodeA.getCurNode(); | curNode = nodeA.getCurNode(); | ||||
assertTrue(curNode.getClass() == DefaultNode.class); | |||||
assertSame(curNode.getClass(), DefaultNode.class); | |||||
DefaultNode dN1 = (DefaultNode)curNode; | DefaultNode dN1 = (DefaultNode)curNode; | ||||
assertTrue(dN1.getClusterNode().getOriginCountMap().containsKey("caller2")); | assertTrue(dN1.getClusterNode().getOriginCountMap().containsKey("caller2")); | ||||
assertTrue(dN1 != dN); | |||||
assertNotSame(dN1, dN); | |||||
if (nodeA != null) { | if (nodeA != null) { | ||||
nodeA.exit(); | nodeA.exit(); |