Skip to content

Commit 3608cc9

Browse files
committed
feat: support merging executor
1 parent 8d2fd1f commit 3608cc9

9 files changed

Lines changed: 1294 additions & 42 deletions

File tree

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
package com.netease.nim.camellia.core.util;
2+
3+
import com.netease.nim.camellia.core.client.env.ProxyEnv;
4+
import com.netease.nim.camellia.core.model.Resource;
5+
import com.netease.nim.camellia.core.model.ResourceTable;
6+
import com.netease.nim.camellia.core.model.operation.ResourceOperation;
7+
import com.netease.nim.camellia.core.model.operation.ResourceReadOperation;
8+
import com.netease.nim.camellia.core.model.operation.ResourceWriteOperation;
9+
import org.junit.Assert;
10+
import org.junit.Test;
11+
12+
import java.util.Arrays;
13+
import java.util.HashMap;
14+
import java.util.HashSet;
15+
import java.util.List;
16+
import java.util.Map;
17+
import java.util.Set;
18+
19+
/**
20+
* Created by caojiajun on 2026/9/23
21+
*/
22+
public class ResourceSelectorTest {
23+
24+
@Test
25+
public void shouldReturnSingleWriteResourceForSimpleTable() {
26+
Resource write1 = new Resource("redis://write-1");
27+
ResourceSelector selector = selector(simpleTable(singleWriteOperation(write1)));
28+
29+
Assert.assertEquals(setOf(write1), setOf(selector.getAllWriteResources()));
30+
}
31+
32+
@Test
33+
public void shouldSumWriteResourcesForMultiWriteToDifferentClusters() {
34+
Resource write1 = new Resource("redis://write-1");
35+
Resource write2 = new Resource("redis://write-2");
36+
ResourceSelector selector = selector(simpleTable(multiWriteOperation(Arrays.asList(write1, write2))));
37+
38+
//双写到2个不同的集群,各算1次
39+
Assert.assertEquals(setOf(write1, write2), setOf(selector.getAllWriteResources()));
40+
}
41+
42+
@Test
43+
public void shouldCountSameClusterOnlyOnce() {
44+
Resource write1 = new Resource("redis://write-1");
45+
ResourceSelector selector = selector(simpleTable(multiWriteOperation(Arrays.asList(write1, write1))));
46+
47+
//同一个集群配置了多次,只算1次
48+
Assert.assertEquals(setOf(write1), setOf(selector.getAllWriteResources()));
49+
}
50+
51+
@Test
52+
public void shouldSumDistinctWriteResourcesForShardingTable() {
53+
Resource write1 = new Resource("redis://write-1");
54+
Resource write2 = new Resource("redis://write-2");
55+
Map<Integer, ResourceOperation> resourceOperationMap = new HashMap<>();
56+
resourceOperationMap.put(0, singleWriteOperation(write1));
57+
resourceOperationMap.put(1, singleWriteOperation(write2));
58+
ResourceSelector selector = selector(shardingTable(2, resourceOperationMap));
59+
60+
//分片之间数据不重叠,需要汇总
61+
Assert.assertEquals(setOf(write1, write2), setOf(selector.getAllWriteResources()));
62+
}
63+
64+
@Test
65+
public void shouldCountSameClusterOnlyOnceAcrossShards() {
66+
Resource write1 = new Resource("redis://write-1");
67+
Resource mirror1 = new Resource("redis://mirror-1");
68+
Map<Integer, ResourceOperation> resourceOperationMap = new HashMap<>();
69+
resourceOperationMap.put(0, multiWriteOperation(Arrays.asList(write1, mirror1)));
70+
resourceOperationMap.put(1, multiWriteOperation(Arrays.asList(write1, mirror1)));
71+
ResourceSelector selector = selector(shardingTable(2, resourceOperationMap));
72+
73+
//多个分片配置了同一组写资源,每个集群只算1次
74+
Assert.assertEquals(setOf(write1, mirror1), setOf(selector.getAllWriteResources()));
75+
}
76+
77+
private ResourceSelector selector(ResourceTable resourceTable) {
78+
return new ResourceSelector(resourceTable, new ProxyEnv.Builder().build());
79+
}
80+
81+
private Set<Resource> setOf(Resource... resources) {
82+
return new HashSet<>(Arrays.asList(resources));
83+
}
84+
85+
private Set<Resource> setOf(List<Resource> resources) {
86+
return new HashSet<>(resources);
87+
}
88+
89+
private ResourceOperation singleWriteOperation(Resource writeResource) {
90+
return new ResourceOperation(new ResourceReadOperation(writeResource), new ResourceWriteOperation(writeResource));
91+
}
92+
93+
private ResourceOperation multiWriteOperation(List<Resource> writeResources) {
94+
return new ResourceOperation(new ResourceReadOperation(writeResources.get(0)), new ResourceWriteOperation(writeResources));
95+
}
96+
97+
private ResourceTable simpleTable(ResourceOperation operation) {
98+
ResourceTable.SimpleTable simpleTable = new ResourceTable.SimpleTable();
99+
simpleTable.setResourceOperation(operation);
100+
return new ResourceTable(simpleTable);
101+
}
102+
103+
private ResourceTable shardingTable(int bucketSize, Map<Integer, ResourceOperation> resourceOperationMap) {
104+
ResourceTable.ShadingTable shadingTable = new ResourceTable.ShadingTable();
105+
shadingTable.setBucketSize(bucketSize);
106+
shadingTable.setResourceOperationMap(resourceOperationMap);
107+
return new ResourceTable(shadingTable);
108+
}
109+
}

‎camellia-toolkits/camellia-tools/src/main/java/com/netease/nim/camellia/tools/executor/CamelliaExecutorMonitor.java‎

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ public class CamelliaExecutorMonitor {
2525
private static final ConcurrentHashMap<String, CamelliaDynamicIsolationExecutor> dynamicIsolationExecutorMap = new ConcurrentHashMap<>();
2626
private static final ConcurrentHashMap<String, CamelliaHashedExecutor> hashedExecutorMap = new ConcurrentHashMap<>();
2727
private static final ConcurrentHashMap<String, CamelliaHashedBatchExecutor<?>> hashedBatchExecutorMap = new ConcurrentHashMap<>();
28+
private static final ConcurrentHashMap<String, CamelliaMergingExecutor<?>> mergingExecutorMap = new ConcurrentHashMap<>();
2829
private static final ConcurrentHashMap<String, CamelliaLinearInitializationExecutor<?, ?>> linerInitializationExecutorMap = new ConcurrentHashMap<>();
2930
private static final ConcurrentHashMap<String, ThreadPoolExecutor> executorMap = new ConcurrentHashMap<>();
3031

@@ -99,6 +100,13 @@ public static void register(CamelliaLinearInitializationExecutor<?, ?> executor)
99100
linerInitializationExecutorMap.put(executor.getName(), executor);
100101
}
101102

103+
/**
104+
* 注册一个CamelliaMergingExecutor
105+
*/
106+
public static void register(CamelliaMergingExecutor<?> executor) {
107+
mergingExecutorMap.put(executor.getName(), executor);
108+
}
109+
102110
private static CamelliaExecutorStatistics statistics = new CamelliaExecutorStatistics();
103111

104112
/**
@@ -211,6 +219,14 @@ private static void calc() {
211219
executorStatsList.add(stats);
212220
}
213221

222+
for (Map.Entry<String, CamelliaMergingExecutor<?>> entry : mergingExecutorMap.entrySet()) {
223+
CamelliaExecutorStatistics.ExecutorStats stats = new CamelliaExecutorStatistics.ExecutorStats();
224+
stats.setName(entry.getKey());
225+
stats.setExecutorType(CamelliaExecutorStatistics.ExecutorType.CamelliaMergingExecutor);
226+
stats.setStats(toStats(entry.getKey(), entry.getValue().getStats()));
227+
executorStatsList.add(stats);
228+
}
229+
214230
for (Map.Entry<String, CamelliaLinearInitializationExecutor<?, ?>> entry : linerInitializationExecutorMap.entrySet()) {
215231
CamelliaExecutorStatistics.ExecutorStats stats = new CamelliaExecutorStatistics.ExecutorStats();
216232
stats.setName(entry.getKey());

‎camellia-toolkits/camellia-tools/src/main/java/com/netease/nim/camellia/tools/executor/CamelliaExecutorStatistics.java‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ public static enum ExecutorType {
9898
CamelliaDynamicExecutor,
9999
CamelliaHashedExecutor,
100100
CamelliaHashedBatchExecutor,
101+
CamelliaMergingExecutor,
101102
CamelliaDynamicIsolationExecutor,
102103
CamelliaLinearInitializationExecutor,
103104
;

0 commit comments

Comments
 (0)