Change the way to transport ability table.

This commit is contained in:
Daydreamer-ia 2022-09-09 18:41:04 +08:00
parent afbfed2954
commit 02bd4872ca
12 changed files with 168 additions and 336 deletions

View File

@ -17,6 +17,8 @@
package com.alibaba.nacos.api.ability.constant;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;
@ -31,44 +33,101 @@ public enum AbilityKey {
/**.
* just for junit test
*/
TEST_1("test_1", 1),
TEST_1("test_1"),
/**.
* just for junit test
*/
TEST_2("test_2", 2);
TEST_2("test_2");
/**.
* the name of a certain ability
*/
private final String name;
private final String keyName;
/**.
* the offset in ability table
*/
private final int offset;
AbilityKey(String name, int offset) {
this.name = name;
this.offset = offset;
AbilityKey(String name) {
this.keyName = name;
}
public String getName() {
return name;
return keyName;
}
public int getOffset() {
return offset;
/**.
* All key set
*/
private static final Map<String, AbilityKey> ALL_ABILITIES;
/**.
* Get all keys
*
* @return all keys
*/
public static Collection<AbilityKey> getAllValues() {
return Collections.unmodifiableCollection(ALL_ABILITIES.values());
}
private static final Map<AbilityKey, Integer> OFFSET_MAP;
/**.
* Get all names
*
* @return all names
*/
public static Collection<String> getAllNames() {
return Collections.unmodifiableCollection(ALL_ABILITIES.keySet());
}
public static Map<AbilityKey, Integer> offset() {
return OFFSET_MAP;
/**.
* Whether contains this name
*
* @param name key name
* @return whether contains
*/
public static boolean isLegalKey(String name) {
return ALL_ABILITIES.containsKey(name);
}
/**.
* Map the string key to enum
*
* @param abilities map
* @return enum map
*/
public static Map<AbilityKey, Boolean> mapEnum(Map<String, Boolean> abilities) {
if (abilities == null || abilities.isEmpty()) {
return Collections.emptyMap();
}
return abilities.entrySet()
.stream()
.filter(entry -> isLegalKey(entry.getKey()))
.collect(Collectors.toMap((entry) -> getEnum(entry.getKey()), Map.Entry::getValue));
}
/**.
* Map the string key to enum
*
* @param abilities map
* @return enum map
*/
public static Map<String, Boolean> mapStr(Map<AbilityKey, Boolean> abilities) {
if (abilities == null || abilities.isEmpty()) {
return Collections.emptyMap();
}
return abilities.entrySet()
.stream()
.collect(Collectors.toMap((entry) -> entry.getKey().getName(), Map.Entry::getValue));
}
/**
* getter to obtain enum
*
* @param key string key
* @return enum
*/
public static AbilityKey getEnum(String key) {
return ALL_ABILITIES.get(key);
}
static {
OFFSET_MAP = Arrays.stream(AbilityKey.values())
.collect(Collectors.toMap(Function.identity(), AbilityKey::getOffset));
ALL_ABILITIES = Arrays.stream(AbilityKey.values()).collect(Collectors.toMap(AbilityKey::getName, Function.identity()));
}
}

View File

@ -17,7 +17,6 @@
package com.alibaba.nacos.api.ability.register;
import com.alibaba.nacos.api.ability.constant.AbilityKey;
import com.alibaba.nacos.api.utils.AbilityTableUtils;
import java.util.Collections;
import java.util.HashMap;
@ -31,25 +30,6 @@ import java.util.Map;
public abstract class AbstractAbilityRegistry {
protected final Map<AbilityKey, Boolean> supportedAbilities = new HashMap<>();
private byte[] abilityBitFlag;
/**.
* Return the static ability bit table
*
* @return ability bit table
*/
public byte[] getAbilityBitFlags() {
return abilityBitFlag.clone();
}
/**.
* put the bit offset to {@link AbstractAbilityRegistry#abilityBitFlag}
*/
protected void init() {
// init the bits table
abilityBitFlag = AbilityTableUtils.getAbilityBiTableBy(AbilityKey.values(), supportedAbilities);
}
/**.
* get static ability current server supports

View File

@ -47,20 +47,6 @@ public class ClientAbilities extends AbstractAbilityRegistry {
// put ability here, which you want current client supports
}
private ClientAbilities() {
// put key to bit offset
init();
}
/**.
* get the ability offset for server
*
* @return ability offset
*/
public static byte[] getBitFlags() {
return INSTANCE.getAbilityBitFlags();
}
/**.
* get static ability current server supports
*

View File

@ -49,20 +49,6 @@ public class ServerAbilities extends AbstractAbilityRegistry {
supportedAbilities.put(AbilityKey.TEST_2, true);
}
private ServerAbilities() {
// put key to bit offset
init();
}
/**.
* get bit table
*
* @return ability offset
*/
public static byte[] getBitFlags() {
return INSTANCE.getAbilityBitFlags();
}
/**.
* get static ability current server supports
*

View File

@ -33,7 +33,7 @@ public class ConnectionSetupRequest extends InternalRequest {
private Map<String, String> labels = new HashMap<>();
private byte[] abilityTable;
private Map<String, Boolean> abilityTable;
public ConnectionSetupRequest() {
}
@ -62,11 +62,11 @@ public class ConnectionSetupRequest extends InternalRequest {
this.tenant = tenant;
}
public byte[] getAbilityTable() {
public Map<String, Boolean> getAbilityTable() {
return abilityTable;
}
public void setAbilityTable(byte[] abilityTable) {
public void setAbilityTable(Map<String, Boolean> abilityTable) {
this.abilityTable = abilityTable;
}
}

View File

@ -16,6 +16,8 @@
package com.alibaba.nacos.api.remote.response;
import java.util.Map;
/**
* response of server check.
*
@ -26,13 +28,13 @@ public class ServerCheckResponse extends Response {
private String connectionId;
private byte[] abilities;
private Map<String, Boolean> abilities;
public ServerCheckResponse() {
}
public ServerCheckResponse(String connectionId, byte[] abilities) {
public ServerCheckResponse(String connectionId, Map<String, Boolean> abilities) {
this.connectionId = connectionId;
this.abilities = abilities;
}
@ -45,11 +47,11 @@ public class ServerCheckResponse extends Response {
this.connectionId = connectionId;
}
public byte[] getAbilities() {
public Map<String, Boolean> getAbilities() {
return abilities;
}
public void setAbilities(byte[] abilities) {
public void setAbilities(Map<String, Boolean> abilities) {
this.abilities = abilities;
}
}

View File

@ -1,132 +0,0 @@
/*
* Copyright 1999-2022 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.api.utils;
import com.alibaba.nacos.api.ability.constant.AbilityKey;
import com.alibaba.nacos.api.ability.register.AbstractAbilityRegistry;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
/**.
* @author Daydreamer
* @description It is used to operate ability table.
* @date 2022/7/12 19:23
**/
public class AbilityTableUtils {
private static final int BASE = 128;
private AbilityTableUtils() {
}
/**.
* get ability bit table from Collection
*
* @param bitCollection bit offset
* @return bit table
*/
public static byte[] getAbilityBitBy(Collection<Integer> bitCollection) {
if (bitCollection.size() == 0) {
return new byte[1];
}
Integer max = Collections.max(bitCollection);
// calculate byte[]
int mark = max % 8;
int length = max / 8 + (mark == 0 ? 0 : 1);
byte[] res = new byte[length];
bitCollection.forEach(offset -> {
int index = offset / 8 + (offset % 8 == 0 ? -1 : 0);
int flag = offset % 8;
if (flag == 0) {
flag = 8;
}
byte x = (byte) (BASE >>> (flag - 1));
res[index] = (byte) (res[index] | x);
});
return res;
}
/**.
* get ability table by bits
*
* @param bits bit flag
* @param offsetMap offset from {@link AbstractAbilityRegistry}
* @return Return the Map containing AbilityTableKey and isRunning.
*/
public static Map<AbilityKey, Boolean> getAbilityTableBy(byte[] bits, Map<AbilityKey, Integer> offsetMap) {
if (bits == null || offsetMap.size() == 0) {
return Collections.emptyMap();
}
int length = bits.length;
Set<Map.Entry<AbilityKey, Integer>> entries = offsetMap.entrySet();
Map<AbilityKey, Boolean> res = new HashMap<>(offsetMap.size());
for (Map.Entry<AbilityKey, Integer> entry : entries) {
AbilityKey abilityKey = entry.getKey();
Integer offset = entry.getValue();
// if not exists
int index = offset / 8 + (offset % 8 == 0 ? -1 : 0);
if (index + 1 > length) {
res.put(abilityKey, Boolean.FALSE);
continue;
}
// find
int flag = offset % 8;
if (flag == 0) {
flag = 8;
}
byte x = (byte) (BASE >>> (flag - 1));
byte tmp = (byte) (x & bits[index]);
res.put(abilityKey, x == tmp);
}
return res;
}
/**.
* get ability bit table by existed ability table and offset map
*
* @param offsetMap offset from {@link AbstractAbilityRegistry}
* @return Return the Map containing AbilityTableKey and isRunning.
*/
public static byte[] getAbilityBiTableBy(Map<AbilityKey, Integer> offsetMap, Map<AbilityKey, Boolean> abilityTable) {
// filter the element which <code>abilityTable</code> don't have or value is false
Map<AbilityKey, Integer> res = offsetMap.entrySet().stream()
.filter(item -> abilityTable.getOrDefault(item.getKey(), false))
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
return getAbilityBitBy(res.values());
}
/**.
* get ability bit table by existed ability table and abilityKeys array
*
* @param abilityKeys abilityKeys array
* @param abilityTable existed ability table
* @return filter ability which value is false in <code>abilityTable</code>
*/
public static byte[] getAbilityBiTableBy(AbilityKey[] abilityKeys, Map<AbilityKey, Boolean> abilityTable) {
// filter the element which <code>abilityTable</code> don't have or value is false
List<AbilityKey> keyList = Arrays.stream(abilityKeys).collect(Collectors.toList());
keyList.removeIf(key -> !abilityTable.getOrDefault(key, false));
return getAbilityBitBy(keyList.stream().map(AbilityKey::getOffset).collect(Collectors.toList()));
}
}

View File

@ -0,0 +1,75 @@
/*
* Copyright 1999-2022 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.api.utils;
import com.alibaba.nacos.api.ability.constant.AbilityKey;
import org.junit.Assert;
import org.junit.Test;
import java.util.HashMap;
import java.util.Map;
/**.
* @author Daydreamer
* @description Ability key test
* @date 2022/9/8 12:27
**/
public class AbilityKeyTest {
@Test
public void testMapStr() {
Map<AbilityKey, Boolean> enumMap = new HashMap<>();
Map<String, Boolean> stringBooleanMap = AbilityKey.mapStr(enumMap);
Assert.assertEquals(0, stringBooleanMap.size());
enumMap.put(AbilityKey.TEST_1, true);
enumMap.put(AbilityKey.TEST_2, false);
stringBooleanMap = AbilityKey.mapStr(enumMap);
Assert.assertEquals(2, stringBooleanMap.size());
Assert.assertTrue(stringBooleanMap.get(AbilityKey.TEST_1.getName()));
Assert.assertFalse(stringBooleanMap.get(AbilityKey.TEST_2.getName()));
enumMap.put(AbilityKey.TEST_2, true);
stringBooleanMap = AbilityKey.mapStr(enumMap);
Assert.assertEquals(2, stringBooleanMap.size());
Assert.assertTrue(stringBooleanMap.get(AbilityKey.TEST_1.getName()));
Assert.assertTrue(stringBooleanMap.get(AbilityKey.TEST_2.getName()));
}
@Test
public void testMapEnum() {
Map<String, Boolean> mapStr = new HashMap<>();
mapStr.put("test-no-existed", true);
Map<AbilityKey, Boolean> enumMap = AbilityKey.mapEnum(mapStr);
Assert.assertEquals(0, enumMap.size());
mapStr.put(AbilityKey.TEST_2.getName(), false);
mapStr.put(AbilityKey.TEST_1.getName(), true);
enumMap = AbilityKey.mapEnum(mapStr);
Assert.assertFalse(enumMap.get(AbilityKey.TEST_2));
Assert.assertTrue(enumMap.get(AbilityKey.TEST_1));
mapStr.clear();
mapStr.put(AbilityKey.TEST_2.getName(), true);
mapStr.put(AbilityKey.TEST_1.getName(), true);
enumMap = AbilityKey.mapEnum(mapStr);
Assert.assertTrue(enumMap.get(AbilityKey.TEST_2));
Assert.assertTrue(enumMap.get(AbilityKey.TEST_1));
}
}

View File

@ -1,118 +0,0 @@
/*
* Copyright 1999-2022 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.api.utils;
import com.alibaba.nacos.api.ability.constant.AbilityKey;
import org.junit.Assert;
import org.junit.Test;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
public class AbilityTableUtilsTest {
@Test
public void testGetAbilityBitBy() {
byte[] abilityBitBy = AbilityTableUtils.getAbilityBitBy(Arrays.asList(1, 8, 9, 17));
Assert.assertEquals(abilityBitBy[0], -127);
Assert.assertEquals(abilityBitBy[1], -128);
Assert.assertEquals(abilityBitBy[2], -128);
// clear
byte[] abilityBits = AbilityTableUtils.getAbilityBitBy(Collections.emptyList());
Assert.assertEquals(abilityBits.length, 1);
Assert.assertEquals(abilityBits[0], 0);
}
@Test
public void testGetAbilityTableBy() {
byte[] bytes = new byte[]{0};
Map<AbilityKey, Boolean> abilityTableBy =
AbilityTableUtils.getAbilityTableBy(bytes, AbilityKey.offset());
Assert.assertEquals(abilityTableBy.getOrDefault(AbilityKey.TEST_1, false), false);
Assert.assertEquals(abilityTableBy.getOrDefault(AbilityKey.TEST_2, false), false);
byte[] bytes1 = new byte[]{-64};
Map<AbilityKey, Boolean> abilityTableBy1 =
AbilityTableUtils.getAbilityTableBy(bytes1, AbilityKey.offset());
Assert.assertEquals(abilityTableBy1.get(AbilityKey.TEST_1), true);
Assert.assertEquals(abilityTableBy1.get(AbilityKey.TEST_2), true);
byte[] bytes2 = new byte[]{-128};
Map<AbilityKey, Boolean> abilityTableBy2 =
AbilityTableUtils.getAbilityTableBy(bytes2, AbilityKey.offset());
Assert.assertEquals(abilityTableBy2.getOrDefault(AbilityKey.TEST_1, false), true);
Assert.assertEquals(abilityTableBy2.getOrDefault(AbilityKey.TEST_2, false), false);
byte[] bytes3 = new byte[]{64};
Map<AbilityKey, Boolean> abilityTableBy3 =
AbilityTableUtils.getAbilityTableBy(bytes3, AbilityKey.offset());
Assert.assertEquals(abilityTableBy3.getOrDefault(AbilityKey.TEST_1, false), false);
Assert.assertEquals(abilityTableBy3.getOrDefault(AbilityKey.TEST_2, false), true);
}
@Test
public void testGetAbilityBiTableBy() {
Map<AbilityKey, Boolean> map = new HashMap<>();
byte[] bytes1 = AbilityTableUtils.getAbilityBiTableBy(AbilityKey.values(), map);
Assert.assertEquals(1, bytes1.length);
Assert.assertEquals(bytes1[0], 0);
map.put(AbilityKey.TEST_1, true);
byte[] bytes2 = AbilityTableUtils.getAbilityBiTableBy(AbilityKey.values(), map);
Assert.assertEquals(1, bytes1.length);
Assert.assertEquals(bytes2[0], -128);
map.put(AbilityKey.TEST_1, false);
map.put(AbilityKey.TEST_2, true);
byte[] bytes3 = AbilityTableUtils.getAbilityBiTableBy(AbilityKey.values(), map);
Assert.assertEquals(1, bytes3.length);
Assert.assertEquals(bytes3[0], 64);
map.put(AbilityKey.TEST_1, true);
byte[] bytes4 = AbilityTableUtils.getAbilityBiTableBy(AbilityKey.values(), map);
Assert.assertEquals(1, bytes4.length);
Assert.assertEquals(bytes4[0], -64);
}
@Test
public void testGetAbilityBiTable() {
Map<AbilityKey, Integer> offset = AbilityKey.offset();
Map<AbilityKey, Boolean> abilities = new HashMap<>();
byte[] bytes1 = AbilityTableUtils.getAbilityBiTableBy(offset, abilities);
Assert.assertEquals(1, bytes1.length);
Assert.assertEquals(bytes1[0], 0);
abilities.put(AbilityKey.TEST_1, true);
byte[] bytes2 = AbilityTableUtils.getAbilityBiTableBy(offset, abilities);
Assert.assertEquals(1, bytes2.length);
Assert.assertEquals(bytes2[0], -128);
abilities.put(AbilityKey.TEST_2, true);
byte[] bytes3 = AbilityTableUtils.getAbilityBiTableBy(offset, abilities);
Assert.assertEquals(1, bytes3.length);
Assert.assertEquals(bytes3[0], -64);
offset = new HashMap<>();
offset.put(AbilityKey.TEST_1, 2);
byte[] bytes4 = AbilityTableUtils.getAbilityBiTableBy(offset, abilities);
Assert.assertEquals(1, bytes4.length);
Assert.assertEquals(bytes4[0], 64);
}
}

View File

@ -31,7 +31,6 @@ import com.alibaba.nacos.api.remote.response.ErrorResponse;
import com.alibaba.nacos.api.remote.response.Response;
import com.alibaba.nacos.api.remote.response.ServerCheckResponse;
import com.alibaba.nacos.api.remote.response.SetupAckResponse;
import com.alibaba.nacos.api.utils.AbilityTableUtils;
import com.alibaba.nacos.common.ability.discover.NacosAbilityManagerHolder;
import com.alibaba.nacos.common.remote.ConnectionType;
import com.alibaba.nacos.common.remote.client.Connection;
@ -354,8 +353,7 @@ public abstract class GrpcClient extends RpcClient {
// if not supported, it will be null
if (serverCheckResponse.getAbilities() != null) {
Map<AbilityKey, Boolean> abilityTable = AbilityTableUtils
.getAbilityTableBy(serverCheckResponse.getAbilities(), AbilityKey.offset());
Map<AbilityKey, Boolean> abilityTable = AbilityKey.mapEnum(serverCheckResponse.getAbilities());
table.setAbility(abilityTable);
// mark
markForSetup.put(serverCheckResponse.getConnectionId(), new CountDownLatch(1));
@ -379,9 +377,7 @@ public abstract class GrpcClient extends RpcClient {
conSetupRequest.setClientVersion(VersionUtils.getFullClientVersion());
conSetupRequest.setLabels(super.getLabels());
// set ability table
byte[] bitTable = AbilityTableUtils.getAbilityBiTableBy(AbilityKey.values(),
NacosAbilityManagerHolder.getInstance().getCurrentRunningAbility());
conSetupRequest.setAbilityTable(bitTable);
conSetupRequest.setAbilityTable(AbilityKey.mapStr(NacosAbilityManagerHolder.getInstance().getCurrentRunningAbility()));
conSetupRequest.setTenant(super.getTenant());
grpcConn.sendRequest(conSetupRequest);
// wait for response

View File

@ -24,7 +24,6 @@ import com.alibaba.nacos.api.remote.request.ConnectResetRequest;
import com.alibaba.nacos.api.remote.request.ConnectionSetupRequest;
import com.alibaba.nacos.api.remote.request.SetupAckRequest;
import com.alibaba.nacos.api.remote.response.Response;
import com.alibaba.nacos.api.utils.AbilityTableUtils;
import com.alibaba.nacos.common.remote.ConnectionType;
import com.alibaba.nacos.common.remote.client.grpc.GrpcUtils;
import com.alibaba.nacos.core.remote.Connection;
@ -125,8 +124,8 @@ public class GrpcBiStreamRequestAcceptor extends BiRequestStreamGrpc.BiRequestSt
Connection connection = new GrpcConnection(metaInfo, responseObserver, CONTEXT_KEY_CHANNEL.get());
// null if supported
if (setUpRequest.getAbilityTable() != null) {
connection.setAbilityTable(AbilityTableUtils.getAbilityTableBy(setUpRequest.getAbilityTable(),
AbilityKey.offset()));
// map to table
connection.setAbilityTable(AbilityKey.mapEnum(setUpRequest.getAbilityTable()));
}
boolean rejectSdkOnStarting = metaInfo.isSdkSource() && !ApplicationUtils.isStarted();

View File

@ -26,7 +26,6 @@ import com.alibaba.nacos.api.remote.request.ServerCheckRequest;
import com.alibaba.nacos.api.remote.response.ErrorResponse;
import com.alibaba.nacos.api.remote.response.Response;
import com.alibaba.nacos.api.remote.response.ServerCheckResponse;
import com.alibaba.nacos.api.utils.AbilityTableUtils;
import com.alibaba.nacos.common.ability.discover.NacosAbilityManagerHolder;
import com.alibaba.nacos.common.remote.client.grpc.GrpcUtils;
import com.alibaba.nacos.core.remote.Connection;
@ -92,8 +91,8 @@ public class GrpcRequestAcceptor extends RequestGrpc.RequestImplBase {
// server check.
if (ServerCheckRequest.class.getSimpleName().equals(type)) {
Payload serverCheckResponseP = GrpcUtils.convert(new ServerCheckResponse(CONTEXT_KEY_CONN_ID.get(),
AbilityTableUtils.getAbilityBiTableBy(AbilityKey.offset(),
NacosAbilityManagerHolder.getInstance().getCurrentRunningAbility())));
// to str map
AbilityKey.mapStr(NacosAbilityManagerHolder.getInstance().getCurrentRunningAbility())));
traceIfNecessary(serverCheckResponseP, false);
responseObserver.onNext(serverCheckResponseP);
responseObserver.onCompleted();