Introduce and evaluate a client presence manager based on sharded pub/sub

This commit is contained in:
Jon Chambers
2024-11-05 15:51:29 -05:00
committed by GitHub
parent 60cdcf5f0c
commit 8c984cbf42
35 changed files with 1339 additions and 56 deletions

View File

@@ -6,6 +6,12 @@
package org.whispersystems.textsecuregcm.util;
import io.lettuce.core.cluster.SlotHash;
import io.lettuce.core.cluster.event.ClusterTopologyChangedEvent;
import io.lettuce.core.cluster.models.partitions.RedisClusterNode;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
public class RedisClusterUtil {
@@ -38,4 +44,51 @@ public class RedisClusterUtil {
public static String getMinimalHashTag(final int slot) {
return HASHES_BY_SLOT[slot];
}
/**
* Returns an array indicating which slots have moved as part of a {@link ClusterTopologyChangedEvent}. The elements
* of the array map to slots in the cluster; for example, if slot 1234 has changed, then element 1234 of the returned
* array will be {@code true}.
*
* @param clusterTopologyChangedEvent the event from which to derive an array of changed slots
*
* @return an array indicating which slots of changed
*/
public static boolean[] getChangedSlots(final ClusterTopologyChangedEvent clusterTopologyChangedEvent) {
final Map<String, RedisClusterNode> beforeNodesById = clusterTopologyChangedEvent.before().stream()
.collect(Collectors.toMap(RedisClusterNode::getNodeId, node -> node));
final Map<String, RedisClusterNode> afterNodesById = clusterTopologyChangedEvent.after().stream()
.collect(Collectors.toMap(RedisClusterNode::getNodeId, node -> node));
final Set<String> nodeIds = new HashSet<>(beforeNodesById.keySet());
nodeIds.addAll(afterNodesById.keySet());
final boolean[] changedSlots = new boolean[SlotHash.SLOT_COUNT];
for (final String nodeId : nodeIds) {
if (beforeNodesById.containsKey(nodeId) && afterNodesById.containsKey(nodeId)) {
// This node was present before and after the topology change, but its slots may have changed
final boolean[] beforeSlots = new boolean[SlotHash.SLOT_COUNT];
beforeNodesById.get(nodeId).getSlots().forEach(slot -> beforeSlots[slot] = true);
final boolean[] afterSlots = new boolean[SlotHash.SLOT_COUNT];
afterNodesById.get(nodeId).getSlots().forEach(slot -> afterSlots[slot] = true);
for (int slot = 0; slot < SlotHash.SLOT_COUNT; slot++) {
changedSlots[slot] |= beforeSlots[slot] ^ afterSlots[slot];
}
} else if (beforeNodesById.containsKey(nodeId)) {
// The node was present before the topology change, but is gone now; all of its slots should be considered
// changed
beforeNodesById.get(nodeId).getSlots().forEach(slot -> changedSlots[slot] = true);
} else {
// The node was present after the change, but wasn't there before; all of its slots should be considered
// changed
afterNodesById.get(nodeId).getSlots().forEach(slot -> changedSlots[slot] = true);
}
}
return changedSlots;
}
}