Signed-off-by: Eric Zhao <sczyh16@gmail.com>master
@@ -18,10 +18,13 @@ package com.alibaba.csp.sentinel.slots.statistic.base; | |||||
import java.util.ArrayList; | import java.util.ArrayList; | ||||
import java.util.List; | import java.util.List; | ||||
import java.util.concurrent.atomic.AtomicReferenceArray; | import java.util.concurrent.atomic.AtomicReferenceArray; | ||||
import java.util.concurrent.locks.ReentrantLock; | |||||
import com.alibaba.csp.sentinel.util.TimeUtil; | import com.alibaba.csp.sentinel.util.TimeUtil; | ||||
/** | /** | ||||
* Basic data structure for statistic metrics. | |||||
* | |||||
* @param <T> type of data wrapper | * @param <T> type of data wrapper | ||||
* @author jialiang.linjl | * @author jialiang.linjl | ||||
* @author Eric Zhao | * @author Eric Zhao | ||||
@@ -32,27 +35,86 @@ public abstract class LeapArray<T> { | |||||
protected int sampleCount; | protected int sampleCount; | ||||
protected int intervalInMs; | protected int intervalInMs; | ||||
protected AtomicReferenceArray<WindowWrap<T>> array; | |||||
protected final AtomicReferenceArray<WindowWrap<T>> array; | |||||
private final ReentrantLock updateLock = new ReentrantLock(); | |||||
public LeapArray(int windowLength, int intervalInSec) { | public LeapArray(int windowLength, int intervalInSec) { | ||||
this.windowLength = windowLength; | this.windowLength = windowLength; | ||||
this.sampleCount = intervalInSec * 1000 / windowLength; | |||||
this.intervalInMs = intervalInSec * 1000; | this.intervalInMs = intervalInSec * 1000; | ||||
this.sampleCount = intervalInMs / windowLength; | |||||
this.array = new AtomicReferenceArray<WindowWrap<T>>(sampleCount); | this.array = new AtomicReferenceArray<WindowWrap<T>>(sampleCount); | ||||
} | } | ||||
/** | |||||
* Get the window at current timestamp. | |||||
* | |||||
* @return the window at current timestamp | |||||
*/ | |||||
public WindowWrap<T> currentWindow() { | public WindowWrap<T> currentWindow() { | ||||
return currentWindow(TimeUtil.currentTimeMillis()); | return currentWindow(TimeUtil.currentTimeMillis()); | ||||
} | } | ||||
/** | |||||
* Create a new bucket. | |||||
* | |||||
* @return the new empty bucket | |||||
*/ | |||||
public abstract T newEmptyBucket(); | |||||
/** | |||||
* Reset current window to provided start time and reset all counters. | |||||
* | |||||
* @param startTime the start time of the window | |||||
* @param windowWrap current window | |||||
* @return new clean window wrap | |||||
*/ | |||||
protected abstract WindowWrap<T> resetWindowTo(WindowWrap<T> windowWrap, long startTime); | |||||
/** | /** | ||||
* Get window at provided timestamp. | * Get window at provided timestamp. | ||||
* | * | ||||
* @param time a valid timestamp | * @param time a valid timestamp | ||||
* @return the window at provided timestamp | * @return the window at provided timestamp | ||||
*/ | */ | ||||
abstract public WindowWrap<T> currentWindow(long time); | |||||
public WindowWrap<T> currentWindow(long time) { | |||||
long timeId = time / windowLength; | |||||
// Calculate current index. | |||||
int idx = (int)(timeId % array.length()); | |||||
// Cut the time to current window start. | |||||
time = time - time % windowLength; | |||||
while (true) { | |||||
WindowWrap<T> old = array.get(idx); | |||||
if (old == null) { | |||||
WindowWrap<T> window = new WindowWrap<T>(windowLength, time, newEmptyBucket()); | |||||
if (array.compareAndSet(idx, null, window)) { | |||||
return window; | |||||
} else { | |||||
Thread.yield(); | |||||
} | |||||
} else if (time == old.windowStart()) { | |||||
return old; | |||||
} else if (time > old.windowStart()) { | |||||
if (updateLock.tryLock()) { | |||||
try { | |||||
// if (old is deprecated) then [LOCK] resetTo currentTime. | |||||
return resetWindowTo(old, time); | |||||
} finally { | |||||
updateLock.unlock(); | |||||
} | |||||
} else { | |||||
Thread.yield(); | |||||
} | |||||
} else if (time < old.windowStart()) { | |||||
// Cannot go through here. | |||||
return new WindowWrap<T>(windowLength, time, newEmptyBucket()); | |||||
} | |||||
} | |||||
} | |||||
public WindowWrap<T> getPreviousWindow(long time) { | public WindowWrap<T> getPreviousWindow(long time) { | ||||
long timeId = (time - windowLength) / windowLength; | long timeId = (time - windowLength) / windowLength; | ||||
@@ -87,16 +149,12 @@ public abstract class LeapArray<T> { | |||||
return old.value(); | return old.value(); | ||||
} | } | ||||
AtomicReferenceArray<WindowWrap<T>> array() { | |||||
return array; | |||||
} | |||||
private boolean isWindowDeprecated(WindowWrap<T> windowWrap) { | private boolean isWindowDeprecated(WindowWrap<T> windowWrap) { | ||||
return TimeUtil.currentTimeMillis() - windowWrap.windowStart() >= intervalInMs; | return TimeUtil.currentTimeMillis() - windowWrap.windowStart() >= intervalInMs; | ||||
} | } | ||||
public List<WindowWrap<T>> list() { | public List<WindowWrap<T>> list() { | ||||
ArrayList<WindowWrap<T>> result = new ArrayList<WindowWrap<T>>(); | |||||
List<WindowWrap<T>> result = new ArrayList<WindowWrap<T>>(); | |||||
for (int i = 0; i < array.length(); i++) { | for (int i = 0; i < array.length(); i++) { | ||||
WindowWrap<T> windowWrap = array.get(i); | WindowWrap<T> windowWrap = array.get(i); | ||||
@@ -110,7 +168,7 @@ public abstract class LeapArray<T> { | |||||
} | } | ||||
public List<T> values() { | public List<T> values() { | ||||
ArrayList<T> result = new ArrayList<T>(); | |||||
List<T> result = new ArrayList<T>(); | |||||
for (int i = 0; i < array.length(); i++) { | for (int i = 0; i < array.length(); i++) { | ||||
WindowWrap<T> windowWrap = array.get(i); | WindowWrap<T> windowWrap = array.get(i); | ||||
@@ -23,7 +23,7 @@ import com.alibaba.csp.sentinel.Constants; | |||||
* @author jialiang.linjl | * @author jialiang.linjl | ||||
* @author Eric Zhao | * @author Eric Zhao | ||||
*/ | */ | ||||
public class Window { | |||||
public class MetricBucket { | |||||
private final LongAdder pass = new LongAdder(); | private final LongAdder pass = new LongAdder(); | ||||
private final LongAdder block = new LongAdder(); | private final LongAdder block = new LongAdder(); | ||||
@@ -33,7 +33,7 @@ public class Window { | |||||
private volatile long minRt; | private volatile long minRt; | ||||
public Window() { | |||||
public MetricBucket() { | |||||
initMinRt(); | initMinRt(); | ||||
} | } | ||||
@@ -46,7 +46,7 @@ public class Window { | |||||
* | * | ||||
* @return new clean window | * @return new clean window | ||||
*/ | */ | ||||
public Window reset() { | |||||
public MetricBucket reset() { | |||||
pass.reset(); | pass.reset(); | ||||
block.reset(); | block.reset(); | ||||
exception.reset(); | exception.reset(); |
@@ -20,27 +20,27 @@ import java.util.List; | |||||
import com.alibaba.csp.sentinel.Constants; | import com.alibaba.csp.sentinel.Constants; | ||||
import com.alibaba.csp.sentinel.node.metric.MetricNode; | import com.alibaba.csp.sentinel.node.metric.MetricNode; | ||||
import com.alibaba.csp.sentinel.slots.statistic.base.Window; | |||||
import com.alibaba.csp.sentinel.slots.statistic.base.MetricBucket; | |||||
import com.alibaba.csp.sentinel.slots.statistic.base.WindowWrap; | import com.alibaba.csp.sentinel.slots.statistic.base.WindowWrap; | ||||
/** | /** | ||||
* The basic metric class in Sentinel using a {@link WindowLeapArray} internal. | |||||
* The basic metric class in Sentinel using a {@link MetricsLeapArray} internal. | |||||
* | * | ||||
* @author jialiang.linjl | * @author jialiang.linjl | ||||
* @author Eric Zhao | * @author Eric Zhao | ||||
*/ | */ | ||||
public class ArrayMetric implements Metric { | public class ArrayMetric implements Metric { | ||||
private final WindowLeapArray data; | |||||
private final MetricsLeapArray data; | |||||
public ArrayMetric(int windowLength, int interval) { | public ArrayMetric(int windowLength, int interval) { | ||||
this.data = new WindowLeapArray(windowLength, interval); | |||||
this.data = new MetricsLeapArray(windowLength, interval); | |||||
} | } | ||||
/** | /** | ||||
* For unit test. | * For unit test. | ||||
*/ | */ | ||||
public ArrayMetric(WindowLeapArray array) { | |||||
public ArrayMetric(MetricsLeapArray array) { | |||||
this.data = array; | this.data = array; | ||||
} | } | ||||
@@ -49,8 +49,8 @@ public class ArrayMetric implements Metric { | |||||
data.currentWindow(); | data.currentWindow(); | ||||
long success = 0; | long success = 0; | ||||
List<Window> list = data.values(); | |||||
for (Window window : list) { | |||||
List<MetricBucket> list = data.values(); | |||||
for (MetricBucket window : list) { | |||||
success += window.success(); | success += window.success(); | ||||
} | } | ||||
return success; | return success; | ||||
@@ -61,8 +61,8 @@ public class ArrayMetric implements Metric { | |||||
data.currentWindow(); | data.currentWindow(); | ||||
long success = 0; | long success = 0; | ||||
List<Window> list = data.values(); | |||||
for (Window window : list) { | |||||
List<MetricBucket> list = data.values(); | |||||
for (MetricBucket window : list) { | |||||
if (window.success() > success) { | if (window.success() > success) { | ||||
success = window.success(); | success = window.success(); | ||||
} | } | ||||
@@ -74,8 +74,8 @@ public class ArrayMetric implements Metric { | |||||
public long exception() { | public long exception() { | ||||
data.currentWindow(); | data.currentWindow(); | ||||
long exception = 0; | long exception = 0; | ||||
List<Window> list = data.values(); | |||||
for (Window window : list) { | |||||
List<MetricBucket> list = data.values(); | |||||
for (MetricBucket window : list) { | |||||
exception += window.exception(); | exception += window.exception(); | ||||
} | } | ||||
return exception; | return exception; | ||||
@@ -85,8 +85,8 @@ public class ArrayMetric implements Metric { | |||||
public long block() { | public long block() { | ||||
data.currentWindow(); | data.currentWindow(); | ||||
long block = 0; | long block = 0; | ||||
List<Window> list = data.values(); | |||||
for (Window window : list) { | |||||
List<MetricBucket> list = data.values(); | |||||
for (MetricBucket window : list) { | |||||
block += window.block(); | block += window.block(); | ||||
} | } | ||||
return block; | return block; | ||||
@@ -96,9 +96,9 @@ public class ArrayMetric implements Metric { | |||||
public long pass() { | public long pass() { | ||||
data.currentWindow(); | data.currentWindow(); | ||||
long pass = 0; | long pass = 0; | ||||
List<Window> list = data.values(); | |||||
List<MetricBucket> list = data.values(); | |||||
for (Window window : list) { | |||||
for (MetricBucket window : list) { | |||||
pass += window.pass(); | pass += window.pass(); | ||||
} | } | ||||
return pass; | return pass; | ||||
@@ -108,8 +108,8 @@ public class ArrayMetric implements Metric { | |||||
public long rt() { | public long rt() { | ||||
data.currentWindow(); | data.currentWindow(); | ||||
long rt = 0; | long rt = 0; | ||||
List<Window> list = data.values(); | |||||
for (Window window : list) { | |||||
List<MetricBucket> list = data.values(); | |||||
for (MetricBucket window : list) { | |||||
rt += window.rt(); | rt += window.rt(); | ||||
} | } | ||||
return rt; | return rt; | ||||
@@ -119,8 +119,8 @@ public class ArrayMetric implements Metric { | |||||
public long minRt() { | public long minRt() { | ||||
data.currentWindow(); | data.currentWindow(); | ||||
long rt = Constants.TIME_DROP_VALVE; | long rt = Constants.TIME_DROP_VALVE; | ||||
List<Window> list = data.values(); | |||||
for (Window window : list) { | |||||
List<MetricBucket> list = data.values(); | |||||
for (MetricBucket window : list) { | |||||
if (window.minRt() < rt) { | if (window.minRt() < rt) { | ||||
rt = window.minRt(); | rt = window.minRt(); | ||||
} | } | ||||
@@ -133,7 +133,7 @@ public class ArrayMetric implements Metric { | |||||
public List<MetricNode> details() { | public List<MetricNode> details() { | ||||
List<MetricNode> details = new ArrayList<MetricNode>(); | List<MetricNode> details = new ArrayList<MetricNode>(); | ||||
data.currentWindow(); | data.currentWindow(); | ||||
for (WindowWrap<Window> window : data.list()) { | |||||
for (WindowWrap<MetricBucket> window : data.list()) { | |||||
if (window == null) { | if (window == null) { | ||||
continue; | continue; | ||||
} | } | ||||
@@ -156,38 +156,38 @@ public class ArrayMetric implements Metric { | |||||
} | } | ||||
@Override | @Override | ||||
public Window[] windows() { | |||||
public MetricBucket[] windows() { | |||||
data.currentWindow(); | data.currentWindow(); | ||||
return data.values().toArray(new Window[data.values().size()]); | |||||
return data.values().toArray(new MetricBucket[data.values().size()]); | |||||
} | } | ||||
@Override | @Override | ||||
public void addException() { | public void addException() { | ||||
WindowWrap<Window> wrap = data.currentWindow(); | |||||
WindowWrap<MetricBucket> wrap = data.currentWindow(); | |||||
wrap.value().addException(); | wrap.value().addException(); | ||||
} | } | ||||
@Override | @Override | ||||
public void addBlock() { | public void addBlock() { | ||||
WindowWrap<Window> wrap = data.currentWindow(); | |||||
WindowWrap<MetricBucket> wrap = data.currentWindow(); | |||||
wrap.value().addBlock(); | wrap.value().addBlock(); | ||||
} | } | ||||
@Override | @Override | ||||
public void addSuccess() { | public void addSuccess() { | ||||
WindowWrap<Window> wrap = data.currentWindow(); | |||||
WindowWrap<MetricBucket> wrap = data.currentWindow(); | |||||
wrap.value().addSuccess(); | wrap.value().addSuccess(); | ||||
} | } | ||||
@Override | @Override | ||||
public void addPass() { | public void addPass() { | ||||
WindowWrap<Window> wrap = data.currentWindow(); | |||||
WindowWrap<MetricBucket> wrap = data.currentWindow(); | |||||
wrap.value().addPass(); | wrap.value().addPass(); | ||||
} | } | ||||
@Override | @Override | ||||
public void addRT(long rt) { | public void addRT(long rt) { | ||||
WindowWrap<Window> wrap = data.currentWindow(); | |||||
WindowWrap<MetricBucket> wrap = data.currentWindow(); | |||||
wrap.value().addRT(rt); | wrap.value().addRT(rt); | ||||
} | } | ||||
@@ -196,7 +196,7 @@ public class ArrayMetric implements Metric { | |||||
data.currentWindow(); | data.currentWindow(); | ||||
StringBuilder sb = new StringBuilder(); | StringBuilder sb = new StringBuilder(); | ||||
sb.append(Thread.currentThread().getId()).append("_"); | sb.append(Thread.currentThread().getId()).append("_"); | ||||
for (WindowWrap<Window> windowWrap : data.list()) { | |||||
for (WindowWrap<MetricBucket> windowWrap : data.list()) { | |||||
sb.append(windowWrap.windowStart()).append(":").append(windowWrap.value().pass()).append(":") | sb.append(windowWrap.windowStart()).append(":").append(windowWrap.value().pass()).append(":") | ||||
.append(windowWrap.value().block()); | .append(windowWrap.value().block()); | ||||
@@ -208,7 +208,7 @@ public class ArrayMetric implements Metric { | |||||
@Override | @Override | ||||
public long previousWindowBlock() { | public long previousWindowBlock() { | ||||
WindowWrap<Window> wrap = data.currentWindow(); | |||||
WindowWrap<MetricBucket> wrap = data.currentWindow(); | |||||
wrap = data.getPreviousWindow(); | wrap = data.getPreviousWindow(); | ||||
if (wrap == null) { | if (wrap == null) { | ||||
return 0; | return 0; | ||||
@@ -218,12 +218,11 @@ public class ArrayMetric implements Metric { | |||||
@Override | @Override | ||||
public long previousWindowPass() { | public long previousWindowPass() { | ||||
WindowWrap<Window> wrap = data.currentWindow(); | |||||
WindowWrap<MetricBucket> wrap = data.currentWindow(); | |||||
wrap = data.getPreviousWindow(); | wrap = data.getPreviousWindow(); | ||||
if (wrap == null) { | if (wrap == null) { | ||||
return 0; | return 0; | ||||
} | } | ||||
return wrap.value().pass(); | return wrap.value().pass(); | ||||
} | } | ||||
} | } |
@@ -18,7 +18,7 @@ package com.alibaba.csp.sentinel.slots.statistic.metric; | |||||
import java.util.List; | import java.util.List; | ||||
import com.alibaba.csp.sentinel.node.metric.MetricNode; | import com.alibaba.csp.sentinel.node.metric.MetricNode; | ||||
import com.alibaba.csp.sentinel.slots.statistic.base.Window; | |||||
import com.alibaba.csp.sentinel.slots.statistic.base.MetricBucket; | |||||
/** | /** | ||||
* Represents a basic structure recording invocation metrics of protected resources. | * Represents a basic structure recording invocation metrics of protected resources. | ||||
@@ -79,7 +79,7 @@ public interface Metric { | |||||
* | * | ||||
* @return window metric array | * @return window metric array | ||||
*/ | */ | ||||
Window[] windows(); | |||||
MetricBucket[] windows(); | |||||
/** | /** | ||||
* Increment by one the current exception count. | * Increment by one the current exception count. | ||||
@@ -0,0 +1,45 @@ | |||||
/* | |||||
* Copyright 1999-2018 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 | |||||
* | |||||
* http://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.statistic.metric; | |||||
import com.alibaba.csp.sentinel.slots.statistic.base.LeapArray; | |||||
import com.alibaba.csp.sentinel.slots.statistic.base.MetricBucket; | |||||
import com.alibaba.csp.sentinel.slots.statistic.base.WindowWrap; | |||||
/** | |||||
* The fundamental data structure for metric statistics in a time window. | |||||
* | |||||
* @author jialiang.linjl | |||||
* @author Eric Zhao | |||||
*/ | |||||
public class MetricsLeapArray extends LeapArray<MetricBucket> { | |||||
public MetricsLeapArray(int windowLengthInMs, int intervalInSec) { | |||||
super(windowLengthInMs, intervalInSec); | |||||
} | |||||
@Override | |||||
public MetricBucket newEmptyBucket() { | |||||
return new MetricBucket(); | |||||
} | |||||
@Override | |||||
protected WindowWrap<MetricBucket> resetWindowTo(WindowWrap<MetricBucket> w, long startTime) { | |||||
w.resetTo(startTime); | |||||
w.value().reset(); | |||||
return w; | |||||
} | |||||
} |
@@ -1,88 +0,0 @@ | |||||
/* | |||||
* Copyright 1999-2018 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 | |||||
* | |||||
* http://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.statistic.metric; | |||||
import java.util.concurrent.locks.ReentrantLock; | |||||
import com.alibaba.csp.sentinel.slots.statistic.base.LeapArray; | |||||
import com.alibaba.csp.sentinel.slots.statistic.base.Window; | |||||
import com.alibaba.csp.sentinel.slots.statistic.base.WindowWrap; | |||||
/** | |||||
* The fundamental data structure for metric statistics in a time window. | |||||
* | |||||
* @author jialiang.linjl | |||||
* @author Eric Zhao | |||||
*/ | |||||
public class WindowLeapArray extends LeapArray<Window> { | |||||
public WindowLeapArray(int windowLengthInMs, int intervalInSec) { | |||||
super(windowLengthInMs, intervalInSec); | |||||
} | |||||
private ReentrantLock addLock = new ReentrantLock(); | |||||
/** | |||||
* Reset current window to provided start time and reset all counters. | |||||
* | |||||
* @param startTime the start time of the window | |||||
* @return new clean window wrap | |||||
*/ | |||||
private WindowWrap<Window> resetWindowTo(WindowWrap<Window> w, long startTime) { | |||||
w.resetTo(startTime); | |||||
w.value().reset(); | |||||
return w; | |||||
} | |||||
@Override | |||||
public WindowWrap<Window> currentWindow(long time) { | |||||
long timeId = time / windowLength; | |||||
// Calculate current index. | |||||
int idx = (int)(timeId % array.length()); | |||||
// Cut the time to current window start. | |||||
time = time - time % windowLength; | |||||
while (true) { | |||||
WindowWrap<Window> old = array.get(idx); | |||||
if (old == null) { | |||||
WindowWrap<Window> window = new WindowWrap<Window>(windowLength, time, new Window()); | |||||
if (array.compareAndSet(idx, null, window)) { | |||||
return window; | |||||
} else { | |||||
Thread.yield(); | |||||
} | |||||
} else if (time == old.windowStart()) { | |||||
return old; | |||||
} else if (time > old.windowStart()) { | |||||
if (addLock.tryLock()) { | |||||
try { | |||||
// if (old is deprecated) then [LOCK] resetTo currentTime. | |||||
return resetWindowTo(old, time); | |||||
} finally { | |||||
addLock.unlock(); | |||||
} | |||||
} else { | |||||
Thread.yield(); | |||||
} | |||||
} else if (time < old.windowStart()) { | |||||
// Cannot go through here. | |||||
return new WindowWrap<Window>(windowLength, time, new Window()); | |||||
} | |||||
} | |||||
} | |||||
} |
@@ -19,10 +19,10 @@ import java.util.ArrayList; | |||||
import org.junit.Test; | import org.junit.Test; | ||||
import com.alibaba.csp.sentinel.slots.statistic.base.Window; | |||||
import com.alibaba.csp.sentinel.slots.statistic.base.MetricBucket; | |||||
import com.alibaba.csp.sentinel.slots.statistic.base.WindowWrap; | import com.alibaba.csp.sentinel.slots.statistic.base.WindowWrap; | ||||
import com.alibaba.csp.sentinel.slots.statistic.metric.ArrayMetric; | import com.alibaba.csp.sentinel.slots.statistic.metric.ArrayMetric; | ||||
import com.alibaba.csp.sentinel.slots.statistic.metric.WindowLeapArray; | |||||
import com.alibaba.csp.sentinel.slots.statistic.metric.MetricsLeapArray; | |||||
import static org.junit.Assert.*; | import static org.junit.Assert.*; | ||||
@@ -40,10 +40,10 @@ public class ArrayMetricTest { | |||||
@Test | @Test | ||||
public void testOperateArrayMetric() { | public void testOperateArrayMetric() { | ||||
WindowLeapArray leapArray = mock(WindowLeapArray.class); | |||||
final WindowWrap<Window> windowWrap = new WindowWrap<Window>(windowLengthInMs, 0, new Window()); | |||||
MetricsLeapArray leapArray = mock(MetricsLeapArray.class); | |||||
final WindowWrap<MetricBucket> windowWrap = new WindowWrap<MetricBucket>(windowLengthInMs, 0, new MetricBucket()); | |||||
when(leapArray.currentWindow()).thenReturn(windowWrap); | when(leapArray.currentWindow()).thenReturn(windowWrap); | ||||
when(leapArray.values()).thenReturn(new ArrayList<Window>() {{ add(windowWrap.value()); }}); | |||||
when(leapArray.values()).thenReturn(new ArrayList<MetricBucket>() {{ add(windowWrap.value()); }}); | |||||
ArrayMetric metric = new ArrayMetric(leapArray); | ArrayMetric metric = new ArrayMetric(leapArray); | ||||
@@ -21,30 +21,30 @@ import java.util.List; | |||||
import java.util.Set; | import java.util.Set; | ||||
import java.util.concurrent.CountDownLatch; | import java.util.concurrent.CountDownLatch; | ||||
import com.alibaba.csp.sentinel.slots.statistic.base.MetricBucket; | |||||
import com.alibaba.csp.sentinel.util.TimeUtil; | import com.alibaba.csp.sentinel.util.TimeUtil; | ||||
import com.alibaba.csp.sentinel.slots.statistic.base.Window; | |||||
import com.alibaba.csp.sentinel.slots.statistic.base.WindowWrap; | import com.alibaba.csp.sentinel.slots.statistic.base.WindowWrap; | ||||
import com.alibaba.csp.sentinel.slots.statistic.metric.WindowLeapArray; | |||||
import com.alibaba.csp.sentinel.slots.statistic.metric.MetricsLeapArray; | |||||
import org.junit.Test; | import org.junit.Test; | ||||
import static org.junit.Assert.*; | import static org.junit.Assert.*; | ||||
/** | /** | ||||
* Test cases for {@link WindowLeapArray}. | |||||
* Test cases for {@link MetricsLeapArray}. | |||||
* | * | ||||
* @author Eric Zhao | * @author Eric Zhao | ||||
*/ | */ | ||||
public class WindowLeapArrayTest { | |||||
public class MetricsLeapArrayTest { | |||||
private final int windowLengthInMs = 1000; | private final int windowLengthInMs = 1000; | ||||
private final int intervalInSec = 2; | private final int intervalInSec = 2; | ||||
@Test | @Test | ||||
public void testNewWindow() { | public void testNewWindow() { | ||||
WindowLeapArray leapArray = new WindowLeapArray(windowLengthInMs, intervalInSec); | |||||
MetricsLeapArray leapArray = new MetricsLeapArray(windowLengthInMs, intervalInSec); | |||||
long time = TimeUtil.currentTimeMillis(); | long time = TimeUtil.currentTimeMillis(); | ||||
WindowWrap<Window> window = leapArray.currentWindow(time); | |||||
WindowWrap<MetricBucket> window = leapArray.currentWindow(time); | |||||
assertEquals(window.windowLength(), windowLengthInMs); | assertEquals(window.windowLength(), windowLengthInMs); | ||||
assertEquals(window.windowStart(), time - time % windowLengthInMs); | assertEquals(window.windowStart(), time - time % windowLengthInMs); | ||||
@@ -54,11 +54,11 @@ public class WindowLeapArrayTest { | |||||
@Test | @Test | ||||
public void testLeapArrayWindowStart() { | public void testLeapArrayWindowStart() { | ||||
WindowLeapArray leapArray = new WindowLeapArray(windowLengthInMs, intervalInSec); | |||||
MetricsLeapArray leapArray = new MetricsLeapArray(windowLengthInMs, intervalInSec); | |||||
long firstTime = TimeUtil.currentTimeMillis(); | long firstTime = TimeUtil.currentTimeMillis(); | ||||
long previousWindowStart = firstTime - firstTime % windowLengthInMs; | long previousWindowStart = firstTime - firstTime % windowLengthInMs; | ||||
WindowWrap<Window> window = leapArray.currentWindow(firstTime); | |||||
WindowWrap<MetricBucket> window = leapArray.currentWindow(firstTime); | |||||
assertEquals(windowLengthInMs, window.windowLength()); | assertEquals(windowLengthInMs, window.windowLength()); | ||||
assertEquals(previousWindowStart, window.windowStart()); | assertEquals(previousWindowStart, window.windowStart()); | ||||
@@ -66,15 +66,15 @@ public class WindowLeapArrayTest { | |||||
@Test | @Test | ||||
public void testWindowAfterOneInterval() { | public void testWindowAfterOneInterval() { | ||||
WindowLeapArray leapArray = new WindowLeapArray(windowLengthInMs, intervalInSec); | |||||
MetricsLeapArray leapArray = new MetricsLeapArray(windowLengthInMs, intervalInSec); | |||||
long firstTime = TimeUtil.currentTimeMillis(); | long firstTime = TimeUtil.currentTimeMillis(); | ||||
long previousWindowStart = firstTime - firstTime % windowLengthInMs; | long previousWindowStart = firstTime - firstTime % windowLengthInMs; | ||||
WindowWrap<Window> window = leapArray.currentWindow(previousWindowStart); | |||||
WindowWrap<MetricBucket> window = leapArray.currentWindow(previousWindowStart); | |||||
assertEquals(windowLengthInMs, window.windowLength()); | assertEquals(windowLengthInMs, window.windowLength()); | ||||
assertEquals(previousWindowStart, window.windowStart()); | assertEquals(previousWindowStart, window.windowStart()); | ||||
Window currentWindow = window.value(); | |||||
MetricBucket currentWindow = window.value(); | |||||
assertNotNull(currentWindow); | assertNotNull(currentWindow); | ||||
currentWindow.addPass(); | currentWindow.addPass(); | ||||
@@ -87,7 +87,7 @@ public class WindowLeapArrayTest { | |||||
window = leapArray.currentWindow(middleTime); | window = leapArray.currentWindow(middleTime); | ||||
assertEquals(previousWindowStart, window.windowStart()); | assertEquals(previousWindowStart, window.windowStart()); | ||||
Window middleWindow = window.value(); | |||||
MetricBucket middleWindow = window.value(); | |||||
middleWindow.addPass(); | middleWindow.addPass(); | ||||
assertSame(currentWindow, middleWindow); | assertSame(currentWindow, middleWindow); | ||||
assertEquals(2L, middleWindow.pass()); | assertEquals(2L, middleWindow.pass()); | ||||
@@ -106,18 +106,18 @@ public class WindowLeapArrayTest { | |||||
@Deprecated | @Deprecated | ||||
public void testWindowDeprecatedRefresh() { | public void testWindowDeprecatedRefresh() { | ||||
WindowLeapArray leapArray = new WindowLeapArray(windowLengthInMs, intervalInSec); | |||||
MetricsLeapArray leapArray = new MetricsLeapArray(windowLengthInMs, intervalInSec); | |||||
final int len = intervalInSec * 1000 / windowLengthInMs; | final int len = intervalInSec * 1000 / windowLengthInMs; | ||||
long firstTime = TimeUtil.currentTimeMillis(); | long firstTime = TimeUtil.currentTimeMillis(); | ||||
List<WindowWrap<Window>> firstIterWindowList = new ArrayList<WindowWrap<Window>>(len); | |||||
List<WindowWrap<MetricBucket>> firstIterWindowList = new ArrayList<WindowWrap<MetricBucket>>(len); | |||||
for (int i = 0; i < len; i++) { | for (int i = 0; i < len; i++) { | ||||
WindowWrap<Window> w = leapArray.currentWindow(firstTime + windowLengthInMs * i); | |||||
WindowWrap<MetricBucket> w = leapArray.currentWindow(firstTime + windowLengthInMs * i); | |||||
w.value().addPass(); | w.value().addPass(); | ||||
firstIterWindowList.add(i, w); | firstIterWindowList.add(i, w); | ||||
} | } | ||||
for (int i = len; i < len * 2; i++) { | for (int i = len; i < len * 2; i++) { | ||||
WindowWrap<Window> w = leapArray.currentWindow(firstTime + windowLengthInMs * i); | |||||
WindowWrap<MetricBucket> w = leapArray.currentWindow(firstTime + windowLengthInMs * i); | |||||
assertNotSame(w, firstIterWindowList.get(i - len)); | assertNotSame(w, firstIterWindowList.get(i - len)); | ||||
} | } | ||||
} | } | ||||
@@ -126,7 +126,7 @@ public class WindowLeapArrayTest { | |||||
public void testMultiThreadUpdateEmptyWindow() throws Exception { | public void testMultiThreadUpdateEmptyWindow() throws Exception { | ||||
final long time = TimeUtil.currentTimeMillis(); | final long time = TimeUtil.currentTimeMillis(); | ||||
final int nThreads = 16; | final int nThreads = 16; | ||||
final WindowLeapArray leapArray = new WindowLeapArray(windowLengthInMs, intervalInSec); | |||||
final MetricsLeapArray leapArray = new MetricsLeapArray(windowLengthInMs, intervalInSec); | |||||
final CountDownLatch latch = new CountDownLatch(nThreads); | final CountDownLatch latch = new CountDownLatch(nThreads); | ||||
Runnable task = new Runnable() { | Runnable task = new Runnable() { | ||||
@Override | @Override | ||||
@@ -147,9 +147,9 @@ public class WindowLeapArrayTest { | |||||
@Test | @Test | ||||
public void testGetPreviousWindow() { | public void testGetPreviousWindow() { | ||||
WindowLeapArray leapArray = new WindowLeapArray(windowLengthInMs, intervalInSec); | |||||
MetricsLeapArray leapArray = new MetricsLeapArray(windowLengthInMs, intervalInSec); | |||||
long time = TimeUtil.currentTimeMillis(); | long time = TimeUtil.currentTimeMillis(); | ||||
WindowWrap<Window> previousWindow = leapArray.currentWindow(time); | |||||
WindowWrap<MetricBucket> previousWindow = leapArray.currentWindow(time); | |||||
assertNull(leapArray.getPreviousWindow(time)); | assertNull(leapArray.getPreviousWindow(time)); | ||||
long nextTime = time + windowLengthInMs; | long nextTime = time + windowLengthInMs; | ||||
@@ -165,16 +165,16 @@ public class WindowLeapArrayTest { | |||||
final int intervalInSec = 1; | final int intervalInSec = 1; | ||||
final int intervalInMs = intervalInSec * 1000; | final int intervalInMs = intervalInSec * 1000; | ||||
WindowLeapArray leapArray = new WindowLeapArray(windowLengthInMs, intervalInSec); | |||||
MetricsLeapArray leapArray = new MetricsLeapArray(windowLengthInMs, intervalInSec); | |||||
long time = TimeUtil.currentTimeMillis(); | long time = TimeUtil.currentTimeMillis(); | ||||
Set<WindowWrap<Window>> windowWraps = new HashSet<WindowWrap<Window>>(); | |||||
Set<WindowWrap<MetricBucket>> windowWraps = new HashSet<WindowWrap<MetricBucket>>(); | |||||
windowWraps.add(leapArray.currentWindow(time)); | windowWraps.add(leapArray.currentWindow(time)); | ||||
windowWraps.add(leapArray.currentWindow(time + windowLengthInMs)); | windowWraps.add(leapArray.currentWindow(time + windowLengthInMs)); | ||||
List<WindowWrap<Window>> list = leapArray.list(); | |||||
for (WindowWrap<Window> wrap : list) { | |||||
List<WindowWrap<MetricBucket>> list = leapArray.list(); | |||||
for (WindowWrap<MetricBucket> wrap : list) { | |||||
assertTrue(windowWraps.contains(wrap)); | assertTrue(windowWraps.contains(wrap)); | ||||
} | } | ||||
@@ -191,18 +191,18 @@ public class WindowLeapArrayTest { | |||||
final int windowLengthInMs = 100; | final int windowLengthInMs = 100; | ||||
final int intervalInSec = 1; | final int intervalInSec = 1; | ||||
WindowLeapArray leapArray = new WindowLeapArray(windowLengthInMs, intervalInSec); | |||||
MetricsLeapArray leapArray = new MetricsLeapArray(windowLengthInMs, intervalInSec); | |||||
long time = TimeUtil.currentTimeMillis(); | long time = TimeUtil.currentTimeMillis(); | ||||
Set<WindowWrap<Window>> windowWraps = new HashSet<WindowWrap<Window>>(); | |||||
Set<WindowWrap<MetricBucket>> windowWraps = new HashSet<WindowWrap<MetricBucket>>(); | |||||
windowWraps.add(leapArray.currentWindow(time)); | windowWraps.add(leapArray.currentWindow(time)); | ||||
windowWraps.add(leapArray.currentWindow(time + windowLengthInMs)); | windowWraps.add(leapArray.currentWindow(time + windowLengthInMs)); | ||||
Thread.sleep(intervalInSec * 1000 + windowLengthInMs * 3); | Thread.sleep(intervalInSec * 1000 + windowLengthInMs * 3); | ||||
List<WindowWrap<Window>> list = leapArray.list(); | |||||
for (WindowWrap<Window> wrap : list) { | |||||
List<WindowWrap<MetricBucket>> list = leapArray.list(); | |||||
for (WindowWrap<MetricBucket> wrap : list) { | |||||
assertTrue(windowWraps.contains(wrap)); | assertTrue(windowWraps.contains(wrap)); | ||||
} | } | ||||
@@ -39,12 +39,6 @@ public class WarmUpFlowTest { | |||||
FlowRuleManager.loadRules(Arrays.asList(flowRule)); | FlowRuleManager.loadRules(Arrays.asList(flowRule)); | ||||
//ContextUtil.enter(null); | |||||
//when(flowRule.selectNodeByRequsterAndStrategy(null, null, null)).thenReturn(value) | |||||
// flowRule.passCheck(null, DefaultNode, acquireCount, args) | |||||
// when(leapArray.values()).thenReturn(new ArrayList<Window>() {{ add(windowWrap.value()); }}); | |||||
ContextUtil.enter("test"); | ContextUtil.enter("test"); | ||||
ContextUtil.exit(); | ContextUtil.exit(); | ||||