Skip to content

Commit 88347cc

Browse files
authored
feat: save and query batch mode (#522)
* feat: batch save and query * feat: optimize dataService init * feat: update mocker match key * feat: update batch query name * feat: update batchSaveMockers name * feat: add unit test * feat: update comment * fix: UT * fix: sonar * feat: set DataService priority by order * fix: UT * fix: UT * fix: UT * fix: UT * fix: UT * feat: add MergeRecordUtil comment
1 parent 41a771f commit 88347cc

File tree

53 files changed

+1022
-544
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

53 files changed

+1022
-544
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ AREX utilizes the advanced Java technique, Instrument API, and is capable of ins
6666
- Auth0 jwt 3.x
6767
- JWTK jjwt 0.1+、jjwt-api 0.10+
6868
#### Netty
69-
- Netty server [3.x, 4.x]
69+
- Netty http server [3.x, 4.x]
7070
#### Config
7171
- Apollo Config [1.x, 2.x]
7272

arex-agent-bootstrap/src/main/java/io/arex/agent/bootstrap/model/ArexMocker.java

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import io.arex.agent.bootstrap.constants.ConfigConstants;
44
import java.util.Collections;
55
import java.util.Map;
6+
import java.util.concurrent.atomic.AtomicBoolean;
67

78
public class ArexMocker implements Mocker {
89
private String id;
@@ -15,9 +16,18 @@ public class ArexMocker implements Mocker {
1516
private long creationTime;
1617
private Mocker.Target targetRequest;
1718
private Mocker.Target targetResponse;
18-
private boolean needMerge;
19+
private transient boolean needMerge;
1920
private String operationName;
2021
private Map<String, String> tags;
22+
private final transient AtomicBoolean matched = new AtomicBoolean(false);
23+
/**
24+
* replay match need
25+
*/
26+
private transient int fuzzyMatchKey;
27+
/**
28+
* replay match need
29+
*/
30+
private transient int accurateMatchKey;
2131

2232
/**
2333
* The default constructor is for deserialization
@@ -141,4 +151,32 @@ public boolean isNeedMerge() {
141151
public void setNeedMerge(boolean needMerge) {
142152
this.needMerge = needMerge;
143153
}
154+
155+
public boolean isMatched() {
156+
return matched.get();
157+
}
158+
159+
public void setMatched(boolean matched) {
160+
this.matched.compareAndSet(false, matched);
161+
}
162+
163+
@Override
164+
public int getAccurateMatchKey() {
165+
return this.accurateMatchKey;
166+
}
167+
168+
@Override
169+
public void setAccurateMatchKey(int accurateMatchKey) {
170+
this.accurateMatchKey = accurateMatchKey;
171+
}
172+
173+
@Override
174+
public int getFuzzyMatchKey() {
175+
return this.fuzzyMatchKey;
176+
}
177+
178+
@Override
179+
public void setFuzzyMatchKey(int fuzzyMatchKey) {
180+
this.fuzzyMatchKey = fuzzyMatchKey;
181+
}
144182
}

arex-agent-bootstrap/src/main/java/io/arex/agent/bootstrap/model/Mocker.java

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,19 @@ default String replayLogTitle() {
117117
return "replay." + getCategoryType().getName();
118118
}
119119

120-
public boolean isNeedMerge();
120+
boolean isNeedMerge();
121121

122-
public void setNeedMerge(boolean needMerge);
122+
void setNeedMerge(boolean needMerge);
123+
124+
boolean isMatched();
125+
126+
void setMatched(boolean matched);
127+
128+
int getAccurateMatchKey();
129+
130+
void setAccurateMatchKey(int accurateMatchKey);
131+
132+
int getFuzzyMatchKey();
133+
134+
void setFuzzyMatchKey(int fuzzyMatchKey);
123135
}

arex-agent-core/src/main/java/io/arex/agent/instrumentation/BaseAgentInstaller.java

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,10 @@
22

33
import io.arex.agent.bootstrap.AgentInstaller;
44
import io.arex.agent.bootstrap.TraceContextManager;
5-
import io.arex.agent.bootstrap.util.CollectionUtil;
65
import io.arex.agent.bootstrap.util.FileUtils;
76
import io.arex.foundation.config.ConfigManager;
87
import io.arex.foundation.healthy.HealthManager;
98
import io.arex.foundation.services.ConfigService;
10-
import io.arex.foundation.services.DataCollectorService;
119
import io.arex.foundation.services.TimerService;
1210
import io.arex.foundation.util.NetUtils;
1311
import io.arex.inst.runtime.context.RecordLimiter;
@@ -114,15 +112,8 @@ private void initDependentComponents() {
114112
initDataCollector();
115113
}
116114
private void initDataCollector() {
117-
DataCollector collector = DataCollectorService.INSTANCE;
118-
if (ConfigManager.INSTANCE.isLocalStorage()) {
119-
List<DataCollector> extendCollectorList = ServiceLoader.load(DataCollector.class, getClassLoader());
120-
if (CollectionUtil.isNotEmpty(extendCollectorList)) {
121-
collector = extendCollectorList.get(0);
122-
}
123-
}
124-
collector.start();
125-
DataService.builder().setDataCollector(collector).build();
115+
List<DataCollector> collectorList = ServiceLoader.load(DataCollector.class, getClassLoader());
116+
DataService.setDataCollector(collectorList);
126117
}
127118

128119
/**

arex-instrumentation-api/src/main/java/io/arex/inst/runtime/context/ArexContext.java

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
package io.arex.inst.runtime.context;
22

3+
import io.arex.agent.bootstrap.model.Mocker;
34
import io.arex.agent.bootstrap.util.ConcurrentHashSet;
45
import io.arex.agent.bootstrap.util.StringUtil;
56
import io.arex.inst.runtime.model.ArexConstants;
6-
import io.arex.inst.runtime.model.MergeDTO;
7-
import io.arex.inst.runtime.util.MergeRecordReplayUtil;
7+
import io.arex.inst.runtime.util.MergeRecordUtil;
88

99
import java.util.*;
1010
import java.util.concurrent.ConcurrentHashMap;
@@ -18,12 +18,12 @@ public class ArexContext {
1818
private final long createTime;
1919
private volatile int sequence;
2020
private Set<Integer> methodSignatureHashList;
21-
private Map<Integer, List<MergeDTO>> cachedReplayResultMap;
21+
private Map<Integer, List<Mocker>> cachedReplayResultMap;
2222
private Map<String, Set<String>> excludeMockTemplate;
2323

2424
private Map<String, Object> attachments = null;
2525

26-
private LinkedBlockingQueue<MergeDTO> mergeRecordQueue;
26+
private LinkedBlockingQueue<Mocker> mergeRecordQueue;
2727

2828
private boolean isRedirectRequest;
2929
private boolean isInvalidCase;
@@ -76,7 +76,7 @@ public Set<Integer> getMethodSignatureHashList() {
7676
return methodSignatureHashList;
7777
}
7878

79-
public Map<Integer, List<MergeDTO>> getCachedReplayResultMap() {
79+
public Map<Integer, List<Mocker>> getCachedReplayResultMap() {
8080
if (cachedReplayResultMap == null) {
8181
cachedReplayResultMap = new ConcurrentHashMap<>();
8282
}
@@ -154,7 +154,7 @@ public boolean isRedirectRequest(String referer) {
154154
return isRedirectRequest;
155155
}
156156

157-
public LinkedBlockingQueue<MergeDTO> getMergeRecordQueue() {
157+
public LinkedBlockingQueue<Mocker> getMergeRecordQueue() {
158158
if (mergeRecordQueue == null) {
159159
mergeRecordQueue = new LinkedBlockingQueue<>(2048);
160160
}
@@ -176,7 +176,7 @@ public void clear() {
176176
}
177177
if (mergeRecordQueue != null) {
178178
// async thread merge record (main entry has ended)
179-
MergeRecordReplayUtil.recordRemain(this);
179+
MergeRecordUtil.recordRemain(this);
180180
mergeRecordQueue.clear();
181181
}
182182
}

arex-instrumentation-api/src/main/java/io/arex/inst/runtime/listener/EventProcessor.java

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import io.arex.agent.bootstrap.util.AdviceClassesCollector;
66
import io.arex.agent.bootstrap.util.NumberUtil;
77
import io.arex.agent.bootstrap.util.StringUtil;
8+
import io.arex.agent.bootstrap.util.ServiceLoader;
89
import io.arex.inst.runtime.model.InitializeEnum;
910
import io.arex.inst.runtime.request.RequestHandlerManager;
1011
import io.arex.inst.runtime.log.LogManager;
@@ -14,12 +15,13 @@
1415
import io.arex.inst.runtime.serializer.Serializer;
1516
import io.arex.inst.runtime.serializer.StringSerializable;
1617
import io.arex.inst.runtime.util.MockUtils;
17-
import io.arex.agent.bootstrap.util.ServiceLoader;
1818

1919
import java.util.List;
2020

2121
import java.util.concurrent.CompletableFuture;
2222
import java.util.concurrent.atomic.AtomicReference;
23+
24+
import io.arex.inst.runtime.util.ReplayUtil;
2325
import org.slf4j.LoggerFactory;
2426

2527
public class EventProcessor {
@@ -45,6 +47,7 @@ public static void onCreate(EventSource source){
4547
return;
4648
}
4749
initContext(source);
50+
loadReplayData();
4851
initClock();
4952
addEnterLog();
5053
}
@@ -134,4 +137,8 @@ private static void initLog(ClassLoader contextClassLoader) {
134137
public static boolean dependencyInitComplete() {
135138
return InitializeEnum.COMPLETE.equals(INIT_DEPENDENCY.get());
136139
}
140+
141+
private static void loadReplayData() {
142+
ReplayUtil.queryMockers();
143+
}
137144
}

arex-instrumentation-api/src/main/java/io/arex/inst/runtime/match/AbstractMatchStrategy.java

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
package io.arex.inst.runtime.match;
22

3-
import io.arex.agent.bootstrap.model.Mocker;
43
import io.arex.inst.runtime.log.LogManager;
5-
import io.arex.inst.runtime.model.MergeDTO;
64

75
public abstract class AbstractMatchStrategy {
86
static final String MATCH_TITLE = "replay.match.fail";
@@ -28,15 +26,4 @@ boolean internalCheck(MatchStrategyContext context) {
2826
return true;
2927
}
3028
abstract void process(MatchStrategyContext context) throws Exception;
31-
32-
Mocker buildMatchedMocker(Mocker requestMocker, MergeDTO mergeReplayDTO) {
33-
if (mergeReplayDTO == null) {
34-
return null;
35-
}
36-
requestMocker.getTargetResponse().setBody(mergeReplayDTO.getResponse());
37-
requestMocker.getTargetResponse().setType(mergeReplayDTO.getResponseType());
38-
requestMocker.getTargetResponse().setAttributes(mergeReplayDTO.getResponseAttributes());
39-
mergeReplayDTO.setMatched(true);
40-
return requestMocker;
41-
}
4229
}

arex-instrumentation-api/src/main/java/io/arex/inst/runtime/match/AccurateMatchStrategy.java

Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -3,51 +3,51 @@
33
import io.arex.agent.bootstrap.model.MockStrategyEnum;
44
import io.arex.agent.bootstrap.model.Mocker;
55
import io.arex.agent.bootstrap.util.StringUtil;
6-
import io.arex.inst.runtime.log.LogManager;
76
import io.arex.inst.runtime.model.MatchStrategyEnum;
8-
import io.arex.inst.runtime.model.MergeDTO;
97
import io.arex.inst.runtime.util.MockUtils;
108

119
import java.util.ArrayList;
1210
import java.util.List;
1311

1412
public class AccurateMatchStrategy extends AbstractMatchStrategy{
15-
private static final String ACCURATE_MATCH_TITLE = "replay.match.accurate";
1613
/**
1714
* search by operationName + requestBody
15+
* priority:
16+
* 1. if matching and not matched before return directly
17+
* 2. if matched before and find-last mode, return matched one
18+
* 3. if matched multiple result, give next fuzzy match
19+
* 4. if strict match mode and not matched, interrupt
1820
*/
1921
void process(MatchStrategyContext context) {
2022
context.setMatchStrategy(MatchStrategyEnum.ACCURATE);
2123
Mocker requestMocker = context.getRequestMocker();
22-
List<MergeDTO> mergeReplayList = context.getMergeReplayList();
24+
List<Mocker> replayList = context.getReplayList();
25+
// operationName + requestBody
2326
int methodSignatureHash = MockUtils.methodSignatureHash(requestMocker);
24-
List<MergeDTO> matchedList = new ArrayList<>(mergeReplayList.size());
25-
for (MergeDTO mergeDTO : mergeReplayList) {
26-
if (methodSignatureHash == mergeDTO.getMethodSignatureHash()) {
27-
matchedList.add(mergeDTO);
27+
List<Mocker> matchedList = new ArrayList<>(replayList.size());
28+
for (Mocker mocker : replayList) {
29+
if (methodSignatureHash == mocker.getAccurateMatchKey()) {
30+
matchedList.add(mocker);
2831
}
2932
}
3033
int matchedCount = matchedList.size();
31-
/*
32-
* 1. unmatched
33-
* 2. matched but find last mode (like dynamicClass)
34-
*/
34+
3535
if (matchedCount == 1) {
36-
if (!matchedList.get(0).isMatched() || MockStrategyEnum.FIND_LAST == context.getMockStrategy()) {
37-
context.setMatchMocker(buildMatchedMocker(requestMocker, matchedList.get(0)));
36+
Mocker matchMocker = matchedList.get(0);
37+
// unmatched or matched but find-last mode (eg: dynamicClass)
38+
if (!matchMocker.isMatched() || MockStrategyEnum.FIND_LAST == context.getMockStrategy()) {
39+
matchMocker.setMatched(true);
40+
context.setMatchMocker(matchMocker);
3841
} else {
39-
LogManager.warn(ACCURATE_MATCH_TITLE, StringUtil.format("accurate match one result, but cannot be used, " +
40-
"reason: matched: %s, mock strategy: %s, methodSignatureHash: %s, category: %s",
41-
Boolean.toString(matchedList.get(0).isMatched()), context.getMockStrategy().name(),
42-
String.valueOf(methodSignatureHash), requestMocker.getCategoryType().getName()));
42+
context.setReason("accurate match one result, but it has already been matched before, so cannot be used");
4343
}
4444
// other modes can only be matched once, so interrupt and not continue next fuzzy match
4545
context.setInterrupt(true);
4646
return;
4747
}
4848
// matched multiple result(like as redis: incr、decr) only retain matched item for next fuzzy match
4949
if (matchedCount > 1) {
50-
context.setMergeReplayList(matchedList);
50+
context.setReplayList(matchedList);
5151
return;
5252
}
5353
// if strict match mode and not matched, interrupt and not continue next fuzzy match

arex-instrumentation-api/src/main/java/io/arex/inst/runtime/match/FuzzyMatchStrategy.java

Lines changed: 18 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,36 +4,41 @@
44
import io.arex.agent.bootstrap.model.Mocker;
55
import io.arex.agent.bootstrap.util.CollectionUtil;
66
import io.arex.inst.runtime.model.MatchStrategyEnum;
7-
import io.arex.inst.runtime.model.MergeDTO;
87

98
import java.util.List;
109

1110
public class FuzzyMatchStrategy extends AbstractMatchStrategy {
1211
/**
1312
* search under the same method signature
14-
* @return unmatched or last one
13+
* replayList is arranged in ascending order by creationTime
14+
* @return not matched before or last one
1515
*/
1616
void process(MatchStrategyContext context) {
1717
context.setMatchStrategy(MatchStrategyEnum.FUZZY);
18-
Mocker requestMocker = context.getRequestMocker();
19-
List<MergeDTO> mergeReplayList = context.getMergeReplayList();
20-
MergeDTO matchedDTO = null;
21-
int size = mergeReplayList.size();
18+
List<Mocker> replayList = context.getReplayList();
19+
Mocker mocker = null;
20+
int size = replayList.size();
2221
for (int i = 0; i < size; i++) {
23-
MergeDTO mergeReplayDTO = mergeReplayList.get(i);
24-
if (!mergeReplayDTO.isMatched()) {
25-
matchedDTO = mergeReplayDTO;
22+
Mocker mockerDTO = replayList.get(i);
23+
if (!mockerDTO.isMatched()) {
24+
mocker = mockerDTO;
2625
break;
2726
}
2827
}
29-
if (matchedDTO == null && MockStrategyEnum.FIND_LAST == context.getMockStrategy()) {
30-
matchedDTO = mergeReplayList.get(size - 1);
28+
if (mocker == null && MockStrategyEnum.FIND_LAST == context.getMockStrategy()) {
29+
mocker = replayList.get(size - 1);
3130
}
32-
context.setMatchMocker(buildMatchedMocker(requestMocker, matchedDTO));
31+
if (mocker != null) {
32+
mocker.setMatched(true);
33+
} else {
34+
context.setReason("fuzzy match no result, all has been matched");
35+
}
36+
37+
context.setMatchMocker(mocker);
3338
}
3439

3540
@Override
3641
boolean internalCheck(MatchStrategyContext context) {
37-
return CollectionUtil.isNotEmpty(context.getMergeReplayList());
42+
return CollectionUtil.isNotEmpty(context.getReplayList());
3843
}
3944
}

0 commit comments

Comments
 (0)