Skip to content

Commit

Permalink
optimize: Caching the ConsistentHashSelector to avoid remapping when …
Browse files Browse the repository at this point in the history
…select every time.
  • Loading branch information
hein-hp committed Dec 23, 2024
1 parent 87885a3 commit 136d2f9
Show file tree
Hide file tree
Showing 2 changed files with 33 additions and 19 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,7 @@
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.List;
import java.util.SortedMap;
import java.util.TreeMap;
import java.util.*;

import org.apache.seata.common.loader.LoadLevel;
import org.apache.seata.config.ConfigurationFactory;
Expand All @@ -38,26 +36,26 @@ public class ConsistentHashLoadBalance implements LoadBalance {
* The constant LOAD_BALANCE_CONSISTENT_HASH_VIRTUAL_NODES.
*/
public static final String LOAD_BALANCE_CONSISTENT_HASH_VIRTUAL_NODES = LoadBalanceFactory.LOAD_BALANCE_PREFIX
+ "virtualNodes";
+ "virtualNodes";
/**
* The constant VIRTUAL_NODES_NUM.
*/
private static final int VIRTUAL_NODES_NUM = ConfigurationFactory.getInstance().getInt(
LOAD_BALANCE_CONSISTENT_HASH_VIRTUAL_NODES, VIRTUAL_NODES_DEFAULT);
LOAD_BALANCE_CONSISTENT_HASH_VIRTUAL_NODES, VIRTUAL_NODES_DEFAULT);

/**
* The ConsistentHashSelectorWrapper that caches a {@link ConsistentHashSelector}.
*/
private volatile ConsistentHashSelectorWrapper selectorWrapper;

@Override
@SuppressWarnings("unchecked")
@Override
public <T> T select(List<T> invokers, String xid) {
if (selectorWrapper == null) {
synchronized (this) {
if (selectorWrapper == null) {
selectorWrapper = new ConsistentHashSelectorWrapper(
new ConsistentHashSelector<>(invokers, VIRTUAL_NODES_NUM), invokers.hashCode());
new ConsistentHashSelector<>(invokers, VIRTUAL_NODES_NUM), invokers);
}
}
}
Expand All @@ -68,25 +66,37 @@ public <T> T select(List<T> invokers, String xid) {
private static final class ConsistentHashSelectorWrapper {

private volatile ConsistentHashSelector selector;
private volatile int invokersHashcode;
// only shared with read
private volatile Set invokers;

public ConsistentHashSelectorWrapper(ConsistentHashSelector selector, int invokersHashcode) {
public ConsistentHashSelectorWrapper(ConsistentHashSelector selector, List invokers) {
this.selector = selector;
this.invokersHashcode = invokersHashcode;
this.invokers = new HashSet<>(invokers);
}

public ConsistentHashSelector getSelector(List invokers) {
int hashCode;
if ((hashCode = invokers.hashCode()) != invokersHashcode) {
if (!equals(invokers)) {
synchronized (this) {
if (hashCode != invokersHashcode) {
if (!equals(invokers)) {
selector = new ConsistentHashSelector(invokers, VIRTUAL_NODES_NUM);
invokersHashcode = hashCode;
this.invokers = new HashSet<>(invokers);
}
}
}
return selector;
}

private boolean equals(List invokers) {
if (invokers.size() != this.invokers.size()) {
return false;
}
for (Object invoker : invokers) {
if (!this.invokers.contains(invoker)) {
return false;
}
}
return true;
}
}

private static final class ConsistentHashSelector<T> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -120,14 +120,18 @@ public void testConsistentHashLoadBalance_select(List<InetSocketAddress> address
@MethodSource("addressProvider")
public void testCachedConsistentHashLoadBalance_select(List<InetSocketAddress> addresses) throws Exception {
ConsistentHashLoadBalance loadBalance = new ConsistentHashLoadBalance();
loadBalance.select(addresses, XID);

List<InetSocketAddress> addresses1 = new ArrayList<>(addresses);
loadBalance.select(addresses1, XID);
Object o1 = getConsistentHashSelectorByReflect(loadBalance);
loadBalance.select(addresses, XID);
List<InetSocketAddress> addresses2 = new ArrayList<>(addresses);
loadBalance.select(addresses2, XID);
Object o2 = getConsistentHashSelectorByReflect(loadBalance);
Assertions.assertEquals(o1, o2);
addresses = new ArrayList<>(addresses);
addresses.remove(ThreadLocalRandom.current().nextInt(addresses.size()));
loadBalance.select(addresses, XID);

List<InetSocketAddress> addresses3 = new ArrayList<>(addresses);
addresses3.remove(ThreadLocalRandom.current().nextInt(addresses.size()));
loadBalance.select(addresses3, XID);
Object o3 = getConsistentHashSelectorByReflect(loadBalance);
Assertions.assertNotEquals(o1, o3);
}
Expand Down

0 comments on commit 136d2f9

Please sign in to comment.