This is an automated email from the ASF dual-hosted git repository.
EarthChen pushed a commit to branch 3.3
in repository https://gitbox.apache.org/repos/asf/dubbo.git
The following commit(s) were added to refs/heads/3.3 by this push:
new 3a3043227f fix: intersect BitList tail invokers in state routing
(#16395)
3a3043227f is described below
commit 3a3043227f5571d25eb2889de5bca22f2914843b
Author: 林桉 <[email protected]>
AuthorDate: Tue Jul 28 16:54:17 2026 +0800
fix: intersect BitList tail invokers in state routing (#16395)
---
.../dubbo/rpc/cluster/router/state/BitList.java | 22 +++++++++++++-----
.../router/condition/ConditionStateRouterTest.java | 27 ++++++++++++++++++++++
.../rpc/cluster/router/state/BitListTest.java | 23 ++++++++++++++++--
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git
a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/state/BitList.java
b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/state/BitList.java
index 013a4010e0..2ecc948b7c 100644
---
a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/state/BitList.java
+++
b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/state/BitList.java
@@ -114,16 +114,26 @@ public class BitList<E> extends AbstractList<E>
implements Cloneable {
}
/**
- * And operation between two bitList. Return a new cloned list.
- * TailList in source bitList will be totally saved even if it is not
appeared in the target bitList.
+ * And operation between two bitList.
*
* @param target target bitList
- * @return this bitList only contains those elements contain in both two
list and source bitList's tailList
+ * @return this bitList only contains elements contained in both lists
*/
public synchronized BitList<E> and(BitList<E> target) {
- rootSet.and(target.rootSet);
- if (target.getTailList() != null) {
- target.getTailList().forEach(this::addToTailList);
+ if (originList == target.originList) {
+ rootSet.and(target.rootSet);
+ } else {
+ BitSet resultSet = new BitSet();
+ for (int bitIndex = rootSet.nextSetBit(0); bitIndex >= 0; bitIndex
= rootSet.nextSetBit(bitIndex + 1)) {
+ if (target.contains(originList.get(bitIndex))) {
+ resultSet.set(bitIndex);
+ }
+ }
+ rootSet.clear();
+ rootSet.or(resultSet);
+ }
+ if (CollectionUtils.isNotEmpty(tailList)) {
+ tailList.removeIf(e -> !target.contains(e));
}
return this;
}
diff --git
a/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/router/condition/ConditionStateRouterTest.java
b/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/router/condition/ConditionStateRouterTest.java
index 09ea3673a8..e9dee0b016 100644
---
a/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/router/condition/ConditionStateRouterTest.java
+++
b/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/router/condition/ConditionStateRouterTest.java
@@ -196,6 +196,33 @@ class ConditionStateRouterTest {
Assertions.assertEquals(1, filteredInvokers6.size());
}
+ @Test
+ void testRoute_shouldFilterTailInvokers() {
+ List<Invoker<String>> originInvokers = new
ArrayList<Invoker<String>>();
+ Invoker<String> targetInvoker =
+ new
MockInvoker<String>(URL.valueOf("dubbo://10.20.3.3:20880/com.foo.BarService"));
+ Invoker<String> tailInvoker =
+ new
MockInvoker<String>(URL.valueOf("dubbo://10.20.3.4:20880/com.foo.BarService"));
+ originInvokers.add(targetInvoker);
+ BitList<Invoker<String>> invokers = new BitList<>(originInvokers);
+ invokers.add(tailInvoker);
+
+ StateRouter<String> router = new ConditionStateRouterFactory()
+ .getRouter(
+ String.class, getRouteUrl("=> host =
10.20.3.3").addParameter(FORCE_KEY, String.valueOf(true)));
+
+ BitList<Invoker<String>> filteredInvokers = router.route(
+ invokers,
+ URL.valueOf("consumer://" + LOCAL_HOST +
"/com.foo.BarService"),
+ new RpcInvocation(),
+ false,
+ new Holder<>());
+
+ Assertions.assertEquals(1, filteredInvokers.size());
+ Assertions.assertTrue(filteredInvokers.contains(targetInvoker));
+ Assertions.assertFalse(filteredInvokers.contains(tailInvoker));
+ }
+
@Test
void testRoute_methodRoute() {
Invocation invocation = new RpcInvocation("getFoo",
"com.foo.BarService", "", new Class<?>[0], new Object[0]);
diff --git
a/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/router/state/BitListTest.java
b/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/router/state/BitListTest.java
index 8885f44533..6b49fd9d75 100644
---
a/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/router/state/BitListTest.java
+++
b/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/router/state/BitListTest.java
@@ -96,10 +96,29 @@ class BitListTest {
aBitList.add("D");
intersectBitList = aBitList.and(bBitList);
- Assertions.assertEquals(3, intersectBitList.size());
+ Assertions.assertEquals(2, intersectBitList.size());
Assertions.assertEquals(totalList.get(0), intersectBitList.get(0));
Assertions.assertEquals(totalList.get(1), intersectBitList.get(1));
- Assertions.assertEquals("D", intersectBitList.get(2));
+ Assertions.assertFalse(intersectBitList.contains("D"));
+ }
+
+ @Test
+ void testIntersectTailList() {
+ List<String> list = Arrays.asList("A", "B");
+ BitList<String> bitList = new BitList<>(list);
+ bitList.add("C");
+ bitList.add("D");
+
+ BitList<String> target = new BitList<>(list);
+ target.remove("B");
+ target.add("D");
+
+ BitList<String> intersectBitList = bitList.and(target);
+ Assertions.assertEquals(2, intersectBitList.size());
+ Assertions.assertEquals("A", intersectBitList.get(0));
+ Assertions.assertEquals("D", intersectBitList.get(1));
+ Assertions.assertFalse(intersectBitList.contains("B"));
+ Assertions.assertFalse(intersectBitList.contains("C"));
}
@Test