![JAR search and dependency download from the Maven repository](/logo.png)
org.infinispan.server.resp.commands.cluster.SHARDS Maven / Gradle / Ivy
Show all versions of infinispan-server-resp Show documentation
package org.infinispan.server.resp.commands.cluster;
import static org.infinispan.server.resp.commands.cluster.CLUSTER.findPhysicalAddress;
import static org.infinispan.server.resp.commands.cluster.CLUSTER.findPort;
import static org.infinispan.server.resp.commands.cluster.CLUSTER.getOnlyIp;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletionStage;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.BiConsumer;
import org.infinispan.AdvancedCache;
import org.infinispan.commons.util.IntSet;
import org.infinispan.commons.util.IntSets;
import org.infinispan.commons.util.concurrent.CompletableFutures;
import org.infinispan.distribution.DistributionManager;
import org.infinispan.distribution.ch.ConsistentHash;
import org.infinispan.manager.CacheManagerInfo;
import org.infinispan.manager.ClusterExecutor;
import org.infinispan.manager.EmbeddedCacheManager;
import org.infinispan.remoting.transport.Address;
import org.infinispan.security.actions.SecurityActions;
import org.infinispan.server.resp.ByteBufPool;
import org.infinispan.server.resp.Resp3Handler;
import org.infinispan.server.resp.RespCommand;
import org.infinispan.server.resp.RespErrorUtil;
import org.infinispan.server.resp.RespRequestHandler;
import org.infinispan.server.resp.commands.Resp3Command;
import org.infinispan.server.resp.serialization.ByteBufferUtils;
import org.infinispan.server.resp.serialization.JavaObjectSerializer;
import org.infinispan.server.resp.serialization.Resp3Response;
import org.infinispan.server.resp.serialization.Resp3Type;
import org.infinispan.server.resp.serialization.RespConstants;
import org.infinispan.topology.CacheTopology;
import io.netty.channel.ChannelHandlerContext;
import net.jcip.annotations.GuardedBy;
/**
* `CLUSTER SHARDS` command.
*
* Use the {@link CacheTopology} and retrieves information based on the {@link ConsistentHash}. We broadcast the
* command to the current topology members to retrieve specific data from the nodes.
*
* @link CLUSTER SHARDS
* @since 15.0
*/
public class SHARDS extends RespCommand implements Resp3Command {
private static final BiConsumer, ByteBufPool> SERIALIZER = (res, alloc) -> {
// Write the size of the response array first.
ByteBufferUtils.writeNumericPrefix(RespConstants.ARRAY, res.size(), alloc);
// Proceed to serialize each element.
for (ShardInformation si : res) {
Resp3Response.write(si, alloc, si);
}
};
@GuardedBy("this")
private CompletionStage> lastExecution = null;
@GuardedBy("this")
private ConsistentHash lastAcceptedHash = null;
public SHARDS() {
super(2, 0, 0, 0);
}
@Override
public CompletionStage perform(Resp3Handler handler, ChannelHandlerContext ctx, List arguments) {
AdvancedCache, ?> respCache = handler.cache();
DistributionManager dm = respCache.getDistributionManager();
if (dm == null) {
RespErrorUtil.customError("This instance has cluster support disabled", handler.allocator());
return handler.myStage();
}
CacheTopology topology = dm.getCacheTopology();
ConsistentHash hash = topology.getCurrentCH();
if (hash == null) {
RespErrorUtil.customError("No consistent hash available", handler.allocator());
return handler.myStage();
}
synchronized (this) {
if (!hash.equals(lastAcceptedHash)) {
lastExecution = readShardsInformation(hash, SecurityActions.getClusterExecutor(respCache),
handler.respServer().segmentSlotRelation().slotWidth());
lastAcceptedHash = hash;
}
}
return handler.stageToReturn(lastExecution, ctx, SERIALIZER);
}
private static CompletionStage> readShardsInformation(ConsistentHash hash, ClusterExecutor executor, int slotWidth) {
Map, IntSet> segmentOwners = new HashMap<>();
for (int i = 0; i < hash.getNumSegments(); i++) {
segmentOwners.computeIfAbsent(hash.locateOwnersForSegment(i), ignore -> IntSets.mutableEmptySet(hash.getNumSegments()))
.add(i);
}
return readNodeInformation(hash.getMembers(), executor)
.thenApply(information -> {
List response = new ArrayList<>();
for (Map.Entry, IntSet> entry : segmentOwners.entrySet()) {
List addresses = entry.getKey();
Map leader = information.get(addresses.get(0));
if (leader == null) {
log.debugf("Not found information for leader: %s", addresses.get(0));
String name = addresses.get(0).toString();
// A health of `loading` mean that the node will be available in the future for traffic.
leader = createNodeSerialized(name, name, 0, "loading");
}
List