tag support multi level (#12673)

This commit is contained in:
carlvine500 2023-08-24 16:51:06 +08:00 committed by GitHub
parent 4e9a0a41fc
commit 679ce4496c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 103 additions and 3 deletions

View File

@ -856,6 +856,23 @@ public final class StringUtils {
return sb.toString();
}
public static String join(final Object[] array, final char delimiter, final int startIndex, final int endIndex) {
if (ArrayUtils.isEmpty(array)) {
return EMPTY_STRING;
}
if (endIndex - startIndex <= 0) {
return EMPTY_STRING;
}
StringBuilder sb = new StringBuilder();
for (int i = startIndex; i < endIndex; i++) {
if (i > 0) {
sb.append(delimiter);
}
sb.append(array[i]);
}
return sb.toString();
}
/**
* parse key-value pair.
*

View File

@ -227,6 +227,10 @@ class StringUtilsTest {
assertEquals(StringUtils.join(s), "123");
assertEquals(StringUtils.join(s, ','), "1,2,3");
assertEquals(StringUtils.join(s, ","), "1,2,3");
assertEquals(StringUtils.join(s, ',', 0, 1), "1");
assertEquals(StringUtils.join(s, ',', 0, 2), "1,2");
assertEquals(StringUtils.join(s, ',', 0, 3), "1,2,3");
assertEquals("", StringUtils.join(s, ',', 2, 0), "1,2");
}
@Test
@ -502,4 +506,4 @@ class StringUtilsTest {
assertTrue(startsWithIgnoreCase("Dubbo.application.name", "dubbo.application."));
}
}
}

View File

@ -36,6 +36,7 @@ import org.apache.dubbo.rpc.cluster.router.state.BitList;
import org.apache.dubbo.rpc.cluster.router.tag.model.TagRouterRule;
import org.apache.dubbo.rpc.cluster.router.tag.model.TagRuleParser;
import java.util.Map;
import java.util.Set;
import java.util.function.Predicate;
@ -52,6 +53,7 @@ public class TagStateRouter<T> extends AbstractStateRouter<T> implements Configu
public static final String NAME = "TAG_ROUTER";
private static final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(TagStateRouter.class);
private static final String RULE_SUFFIX = ".tag-router";
public static final char TAG_SEPERATOR = '|';
private volatile TagRouterRule tagRouterRule;
private String application;
@ -106,7 +108,8 @@ public class TagStateRouter<T> extends AbstractStateRouter<T> implements Configu
// if we are requesting for a Provider with a specific tag
if (StringUtils.isNotEmpty(tag)) {
Set<String> addresses = tagRouterRuleCopy.getTagnameToAddresses().get(tag);
Map<String, Set<String>> tagnameToAddresses = tagRouterRuleCopy.getTagnameToAddresses();
Set<String> addresses = selectAddressByTagLevel(tagnameToAddresses, tag, isForceUseTag(invocation));
// filter by dynamic tag group first
if (addresses != null) { // null means tag not set
result = filterInvoker(invokers, invoker -> addressMatches(invoker.getUrl(), addresses));
@ -306,4 +309,34 @@ public class TagStateRouter<T> extends AbstractStateRouter<T> implements Configu
public void setTagRouterRule(TagRouterRule tagRouterRule) {
this.tagRouterRule = tagRouterRule;
}
/**
* select addresses by tag with level
* <p>
* example:
* selector=beta|team1|partner1
* step1.select tagAddresses with selector=beta|team1|partner1, if result is empty, then run step2
* step2.select tagAddresses with selector=beta|team1, if result is empty, then run step3
* step3.select tagAddresses with selector=beta, if result is empty, result is null
* </p>
*
* @param tagAddresses
* @param tagSelector eg: beta|team1|partner1
* @return
*/
public static Set<String> selectAddressByTagLevel(Map<String, Set<String>> tagAddresses, String tagSelector, boolean isForce) {
if (isForce || StringUtils.isNotContains(tagSelector, TAG_SEPERATOR)) {
return tagAddresses.get(tagSelector);
}
String[] selectors = StringUtils.split(tagSelector, TAG_SEPERATOR);
for (int i = selectors.length; i > 0; i--) {
String selectorTmp = StringUtils.join(selectors, TAG_SEPERATOR, 0, i);
Set<String> addresses = tagAddresses.get(selectorTmp);
if (CollectionUtils.isNotEmpty(addresses)) {
return addresses;
}
}
return null;
}
}

View File

@ -24,7 +24,6 @@ import org.apache.dubbo.common.utils.Holder;
import org.apache.dubbo.rpc.Invoker;
import org.apache.dubbo.rpc.RpcInvocation;
import org.apache.dubbo.rpc.cluster.router.MockInvoker;
//import org.apache.dubbo.rpc.cluster.router.mesh.util.TracingContextProvider;
import org.apache.dubbo.rpc.cluster.router.state.BitList;
import org.apache.dubbo.rpc.cluster.router.state.StateRouter;
import org.apache.dubbo.rpc.cluster.router.tag.model.TagRouterRule;
@ -32,13 +31,17 @@ import org.apache.dubbo.rpc.cluster.router.tag.model.TagRuleParser;
import org.apache.dubbo.rpc.model.ApplicationModel;
import org.apache.dubbo.rpc.model.ModuleModel;
import com.google.common.collect.Sets;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import static org.apache.dubbo.common.constants.CommonConstants.TAG_KEY;
import static org.mockito.Mockito.when;
@ -256,4 +259,47 @@ class TagStateRouterTest {
TagRouterRule tagRouterRule = TagRuleParser.parse(tagRouterRuleConfig);
return tagRouterRule;
}
@Test
public void tagMultiLevelTest() {
String tagSelector = "beta|team1|partner1";
Set<String> address1 = Sets.newHashSet("192.168.5.1:20880");
Map<String, Set<String>> tagAddresses = new HashMap<>();
tagAddresses.put("beta", address1);
Assertions.assertEquals(address1, TagStateRouter.selectAddressByTagLevel(tagAddresses, tagSelector, false));
Set<String> address2 = Sets.newHashSet("192.168.5.2:20880");
tagAddresses.put("beta|team1", address2);
Assertions.assertEquals(address2, TagStateRouter.selectAddressByTagLevel(tagAddresses, tagSelector, false));
Set<String> address3 = Sets.newHashSet("192.168.5.3:20880");
tagAddresses.put("beta|team1|partner1", address3);
Assertions.assertEquals(address3, TagStateRouter.selectAddressByTagLevel(tagAddresses, tagSelector, false));
tagSelector = "beta";
Assertions.assertEquals(address1, TagStateRouter.selectAddressByTagLevel(tagAddresses, tagSelector, false));
tagSelector = "beta|team1";
Assertions.assertEquals(address2, TagStateRouter.selectAddressByTagLevel(tagAddresses, tagSelector, false));
tagSelector = "beta|team1|partner1";
Assertions.assertEquals(address3, TagStateRouter.selectAddressByTagLevel(tagAddresses, tagSelector, false));
tagSelector = "beta2";
Assertions.assertNull(TagStateRouter.selectAddressByTagLevel(tagAddresses, tagSelector, false));
tagSelector = "beta|team2";
Assertions.assertEquals(address1, TagStateRouter.selectAddressByTagLevel(tagAddresses, tagSelector, false));
tagSelector = "beta|team1|partner2";
Assertions.assertEquals(address2, TagStateRouter.selectAddressByTagLevel(tagAddresses, tagSelector, false));
}
@Test
public void tagLevelForceTest() {
Set<String> addresses = Sets.newHashSet("192.168.1.223:20880");
Map<String, Set<String>> tagAddresses = new HashMap<>();
tagAddresses.put("beta", addresses);
Set<String> selectedAddresses = TagStateRouter.selectAddressByTagLevel(tagAddresses, "beta", true);
Assertions.assertEquals(addresses, selectedAddresses);
}
}