Skip to content

Commit 5490549

Browse files
committed
Refactor LeapArray to reuse code for current bucket
Signed-off-by: Eric Zhao <[email protected]>
1 parent ca2f4d9 commit 5490549

File tree

9 files changed

+179
-171
lines changed

9 files changed

+179
-171
lines changed

sentinel-core/src/main/java/com/alibaba/csp/sentinel/slots/statistic/base/LeapArray.java

+67-9
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,13 @@
1818
import java.util.ArrayList;
1919
import java.util.List;
2020
import java.util.concurrent.atomic.AtomicReferenceArray;
21+
import java.util.concurrent.locks.ReentrantLock;
2122

2223
import com.alibaba.csp.sentinel.util.TimeUtil;
2324

2425
/**
26+
* Basic data structure for statistic metrics.
27+
*
2528
* @param <T> type of data wrapper
2629
* @author jialiang.linjl
2730
* @author Eric Zhao
@@ -32,27 +35,86 @@ public abstract class LeapArray<T> {
3235
protected int sampleCount;
3336
protected int intervalInMs;
3437

35-
protected AtomicReferenceArray<WindowWrap<T>> array;
38+
protected final AtomicReferenceArray<WindowWrap<T>> array;
39+
40+
private final ReentrantLock updateLock = new ReentrantLock();
3641

3742
public LeapArray(int windowLength, int intervalInSec) {
3843
this.windowLength = windowLength;
39-
this.sampleCount = intervalInSec * 1000 / windowLength;
4044
this.intervalInMs = intervalInSec * 1000;
45+
this.sampleCount = intervalInMs / windowLength;
4146

4247
this.array = new AtomicReferenceArray<WindowWrap<T>>(sampleCount);
4348
}
4449

50+
/**
51+
* Get the window at current timestamp.
52+
*
53+
* @return the window at current timestamp
54+
*/
4555
public WindowWrap<T> currentWindow() {
4656
return currentWindow(TimeUtil.currentTimeMillis());
4757
}
4858

59+
/**
60+
* Create a new bucket.
61+
*
62+
* @return the new empty bucket
63+
*/
64+
public abstract T newEmptyBucket();
65+
66+
/**
67+
* Reset current window to provided start time and reset all counters.
68+
*
69+
* @param startTime the start time of the window
70+
* @param windowWrap current window
71+
* @return new clean window wrap
72+
*/
73+
protected abstract WindowWrap<T> resetWindowTo(WindowWrap<T> windowWrap, long startTime);
74+
4975
/**
5076
* Get window at provided timestamp.
5177
*
5278
* @param time a valid timestamp
5379
* @return the window at provided timestamp
5480
*/
55-
abstract public WindowWrap<T> currentWindow(long time);
81+
public WindowWrap<T> currentWindow(long time) {
82+
long timeId = time / windowLength;
83+
// Calculate current index.
84+
int idx = (int)(timeId % array.length());
85+
86+
// Cut the time to current window start.
87+
time = time - time % windowLength;
88+
89+
while (true) {
90+
WindowWrap<T> old = array.get(idx);
91+
if (old == null) {
92+
WindowWrap<T> window = new WindowWrap<T>(windowLength, time, newEmptyBucket());
93+
if (array.compareAndSet(idx, null, window)) {
94+
return window;
95+
} else {
96+
Thread.yield();
97+
}
98+
} else if (time == old.windowStart()) {
99+
return old;
100+
} else if (time > old.windowStart()) {
101+
if (updateLock.tryLock()) {
102+
try {
103+
// if (old is deprecated) then [LOCK] resetTo currentTime.
104+
return resetWindowTo(old, time);
105+
} finally {
106+
updateLock.unlock();
107+
}
108+
} else {
109+
Thread.yield();
110+
}
111+
112+
} else if (time < old.windowStart()) {
113+
// Cannot go through here.
114+
return new WindowWrap<T>(windowLength, time, newEmptyBucket());
115+
}
116+
}
117+
}
56118

57119
public WindowWrap<T> getPreviousWindow(long time) {
58120
long timeId = (time - windowLength) / windowLength;
@@ -87,16 +149,12 @@ public T getWindowValue(long time) {
87149
return old.value();
88150
}
89151

90-
AtomicReferenceArray<WindowWrap<T>> array() {
91-
return array;
92-
}
93-
94152
private boolean isWindowDeprecated(WindowWrap<T> windowWrap) {
95153
return TimeUtil.currentTimeMillis() - windowWrap.windowStart() >= intervalInMs;
96154
}
97155

98156
public List<WindowWrap<T>> list() {
99-
ArrayList<WindowWrap<T>> result = new ArrayList<WindowWrap<T>>();
157+
List<WindowWrap<T>> result = new ArrayList<WindowWrap<T>>();
100158

101159
for (int i = 0; i < array.length(); i++) {
102160
WindowWrap<T> windowWrap = array.get(i);
@@ -110,7 +168,7 @@ public List<WindowWrap<T>> list() {
110168
}
111169

112170
public List<T> values() {
113-
ArrayList<T> result = new ArrayList<T>();
171+
List<T> result = new ArrayList<T>();
114172

115173
for (int i = 0; i < array.length(); i++) {
116174
WindowWrap<T> windowWrap = array.get(i);

sentinel-core/src/main/java/com/alibaba/csp/sentinel/slots/statistic/base/Window.java renamed to sentinel-core/src/main/java/com/alibaba/csp/sentinel/slots/statistic/base/MetricBucket.java

+3-3
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
* @author jialiang.linjl
2424
* @author Eric Zhao
2525
*/
26-
public class Window {
26+
public class MetricBucket {
2727

2828
private final LongAdder pass = new LongAdder();
2929
private final LongAdder block = new LongAdder();
@@ -33,7 +33,7 @@ public class Window {
3333

3434
private volatile long minRt;
3535

36-
public Window() {
36+
public MetricBucket() {
3737
initMinRt();
3838
}
3939

@@ -46,7 +46,7 @@ private void initMinRt() {
4646
*
4747
* @return new clean window
4848
*/
49-
public Window reset() {
49+
public MetricBucket reset() {
5050
pass.reset();
5151
block.reset();
5252
exception.reset();

sentinel-core/src/main/java/com/alibaba/csp/sentinel/slots/statistic/metric/ArrayMetric.java

+30-31
Original file line numberDiff line numberDiff line change
@@ -20,27 +20,27 @@
2020

2121
import com.alibaba.csp.sentinel.Constants;
2222
import com.alibaba.csp.sentinel.node.metric.MetricNode;
23-
import com.alibaba.csp.sentinel.slots.statistic.base.Window;
23+
import com.alibaba.csp.sentinel.slots.statistic.base.MetricBucket;
2424
import com.alibaba.csp.sentinel.slots.statistic.base.WindowWrap;
2525

2626
/**
27-
* The basic metric class in Sentinel using a {@link WindowLeapArray} internal.
27+
* The basic metric class in Sentinel using a {@link MetricsLeapArray} internal.
2828
*
2929
* @author jialiang.linjl
3030
* @author Eric Zhao
3131
*/
3232
public class ArrayMetric implements Metric {
3333

34-
private final WindowLeapArray data;
34+
private final MetricsLeapArray data;
3535

3636
public ArrayMetric(int windowLength, int interval) {
37-
this.data = new WindowLeapArray(windowLength, interval);
37+
this.data = new MetricsLeapArray(windowLength, interval);
3838
}
3939

4040
/**
4141
* For unit test.
4242
*/
43-
public ArrayMetric(WindowLeapArray array) {
43+
public ArrayMetric(MetricsLeapArray array) {
4444
this.data = array;
4545
}
4646

@@ -49,8 +49,8 @@ public long success() {
4949
data.currentWindow();
5050
long success = 0;
5151

52-
List<Window> list = data.values();
53-
for (Window window : list) {
52+
List<MetricBucket> list = data.values();
53+
for (MetricBucket window : list) {
5454
success += window.success();
5555
}
5656
return success;
@@ -61,8 +61,8 @@ public long maxSuccess() {
6161
data.currentWindow();
6262
long success = 0;
6363

64-
List<Window> list = data.values();
65-
for (Window window : list) {
64+
List<MetricBucket> list = data.values();
65+
for (MetricBucket window : list) {
6666
if (window.success() > success) {
6767
success = window.success();
6868
}
@@ -74,8 +74,8 @@ public long maxSuccess() {
7474
public long exception() {
7575
data.currentWindow();
7676
long exception = 0;
77-
List<Window> list = data.values();
78-
for (Window window : list) {
77+
List<MetricBucket> list = data.values();
78+
for (MetricBucket window : list) {
7979
exception += window.exception();
8080
}
8181
return exception;
@@ -85,8 +85,8 @@ public long exception() {
8585
public long block() {
8686
data.currentWindow();
8787
long block = 0;
88-
List<Window> list = data.values();
89-
for (Window window : list) {
88+
List<MetricBucket> list = data.values();
89+
for (MetricBucket window : list) {
9090
block += window.block();
9191
}
9292
return block;
@@ -96,9 +96,9 @@ public long block() {
9696
public long pass() {
9797
data.currentWindow();
9898
long pass = 0;
99-
List<Window> list = data.values();
99+
List<MetricBucket> list = data.values();
100100

101-
for (Window window : list) {
101+
for (MetricBucket window : list) {
102102
pass += window.pass();
103103
}
104104
return pass;
@@ -108,8 +108,8 @@ public long pass() {
108108
public long rt() {
109109
data.currentWindow();
110110
long rt = 0;
111-
List<Window> list = data.values();
112-
for (Window window : list) {
111+
List<MetricBucket> list = data.values();
112+
for (MetricBucket window : list) {
113113
rt += window.rt();
114114
}
115115
return rt;
@@ -119,8 +119,8 @@ public long rt() {
119119
public long minRt() {
120120
data.currentWindow();
121121
long rt = Constants.TIME_DROP_VALVE;
122-
List<Window> list = data.values();
123-
for (Window window : list) {
122+
List<MetricBucket> list = data.values();
123+
for (MetricBucket window : list) {
124124
if (window.minRt() < rt) {
125125
rt = window.minRt();
126126
}
@@ -133,7 +133,7 @@ public long minRt() {
133133
public List<MetricNode> details() {
134134
List<MetricNode> details = new ArrayList<MetricNode>();
135135
data.currentWindow();
136-
for (WindowWrap<Window> window : data.list()) {
136+
for (WindowWrap<MetricBucket> window : data.list()) {
137137
if (window == null) {
138138
continue;
139139
}
@@ -156,38 +156,38 @@ public List<MetricNode> details() {
156156
}
157157

158158
@Override
159-
public Window[] windows() {
159+
public MetricBucket[] windows() {
160160
data.currentWindow();
161-
return data.values().toArray(new Window[data.values().size()]);
161+
return data.values().toArray(new MetricBucket[data.values().size()]);
162162
}
163163

164164
@Override
165165
public void addException() {
166-
WindowWrap<Window> wrap = data.currentWindow();
166+
WindowWrap<MetricBucket> wrap = data.currentWindow();
167167
wrap.value().addException();
168168
}
169169

170170
@Override
171171
public void addBlock() {
172-
WindowWrap<Window> wrap = data.currentWindow();
172+
WindowWrap<MetricBucket> wrap = data.currentWindow();
173173
wrap.value().addBlock();
174174
}
175175

176176
@Override
177177
public void addSuccess() {
178-
WindowWrap<Window> wrap = data.currentWindow();
178+
WindowWrap<MetricBucket> wrap = data.currentWindow();
179179
wrap.value().addSuccess();
180180
}
181181

182182
@Override
183183
public void addPass() {
184-
WindowWrap<Window> wrap = data.currentWindow();
184+
WindowWrap<MetricBucket> wrap = data.currentWindow();
185185
wrap.value().addPass();
186186
}
187187

188188
@Override
189189
public void addRT(long rt) {
190-
WindowWrap<Window> wrap = data.currentWindow();
190+
WindowWrap<MetricBucket> wrap = data.currentWindow();
191191
wrap.value().addRT(rt);
192192
}
193193

@@ -196,7 +196,7 @@ public void debugQps() {
196196
data.currentWindow();
197197
StringBuilder sb = new StringBuilder();
198198
sb.append(Thread.currentThread().getId()).append("_");
199-
for (WindowWrap<Window> windowWrap : data.list()) {
199+
for (WindowWrap<MetricBucket> windowWrap : data.list()) {
200200

201201
sb.append(windowWrap.windowStart()).append(":").append(windowWrap.value().pass()).append(":")
202202
.append(windowWrap.value().block());
@@ -208,7 +208,7 @@ public void debugQps() {
208208

209209
@Override
210210
public long previousWindowBlock() {
211-
WindowWrap<Window> wrap = data.currentWindow();
211+
WindowWrap<MetricBucket> wrap = data.currentWindow();
212212
wrap = data.getPreviousWindow();
213213
if (wrap == null) {
214214
return 0;
@@ -218,12 +218,11 @@ public long previousWindowBlock() {
218218

219219
@Override
220220
public long previousWindowPass() {
221-
WindowWrap<Window> wrap = data.currentWindow();
221+
WindowWrap<MetricBucket> wrap = data.currentWindow();
222222
wrap = data.getPreviousWindow();
223223
if (wrap == null) {
224224
return 0;
225225
}
226226
return wrap.value().pass();
227227
}
228-
229228
}

sentinel-core/src/main/java/com/alibaba/csp/sentinel/slots/statistic/metric/Metric.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
import java.util.List;
1919

2020
import com.alibaba.csp.sentinel.node.metric.MetricNode;
21-
import com.alibaba.csp.sentinel.slots.statistic.base.Window;
21+
import com.alibaba.csp.sentinel.slots.statistic.base.MetricBucket;
2222

2323
/**
2424
* Represents a basic structure recording invocation metrics of protected resources.
@@ -79,7 +79,7 @@ public interface Metric {
7979
*
8080
* @return window metric array
8181
*/
82-
Window[] windows();
82+
MetricBucket[] windows();
8383

8484
/**
8585
* Increment by one the current exception count.

0 commit comments

Comments
 (0)