package org.infinispan.query.affinity;
import java.util.Set;
import org.infinispan.Cache;
import org.infinispan.distribution.DistributionManager;
import org.infinispan.distribution.ch.ConsistentHash;
import org.infinispan.factories.annotations.Inject;
import org.infinispan.notifications.Listener;
import org.infinispan.notifications.Listener.Observation;
import org.infinispan.notifications.cachelistener.annotation.TopologyChanged;
import org.infinispan.notifications.cachelistener.event.TopologyChangedEvent;
import org.infinispan.query.logging.Log;
import org.infinispan.remoting.transport.Address;
import org.infinispan.util.logging.LogFactory;
/**
* @see ShardAllocatorManager
* @since 9.0
*/
@Listener(observation = Observation.POST)
public final class ShardAllocationManagerImpl implements ShardAllocatorManager {
private static final Log logger = LogFactory.getLog(ShardAllocationManagerImpl.class, Log.class);
private DistributionManager distributionManager;
private volatile boolean initialized;
private int numSegments;
private Integer numShards;
private volatile ShardDistribution shardDistribution;
@Inject
public void inject(Cache<?, ?> cache, DistributionManager distributionManager) {
this.distributionManager = distributionManager;
cache.addListener(this);
}
@Override
public String getShardFromSegment(int segment) {
String shardId = this.getShardDistribution().getShardFromSegment(segment);
logger.debugf("ShardId for segment %d: %s", segment, shardId);
return shardId;
}
private ShardDistribution buildShardDistribution(ConsistentHash consistentHash) {
return ShardDistributionFactory.build(numShards, numSegments, consistentHash);
}
private ShardDistribution getShardDistribution() {
if (shardDistribution == null) {
shardDistribution = this.buildShardDistribution(
distributionManager == null ? null : distributionManager.getWriteConsistentHash());
}
return shardDistribution;
}
@Override
public Address getOwner(String shardId) {
return this.getShardDistribution().getOwner(shardId);
}
@Override
public String getShardFromKey(Object key) {
int segment = distributionManager.getCacheTopology().getSegment(key);
logger.debugf("Segment for key %s: %d", key, segment);
return this.getShardDistribution().getShardFromSegment(segment);
}
@Override
public void initialize(Integer numberOfShards, int numSegments) {
this.numSegments = numSegments;
this.numShards = numberOfShards == null ? numSegments : numberOfShards;
initialized = true;
}
@Override
public Set<String> getShards() {
Set<String> shards = this.getShardDistribution().getShardsIdentifiers();
logger.debugf("AllShards:%s", shards);
return shards;
}
@Override
public Set<String> getShardsForModification(Address address) {
Set<String> shards = this.getShardDistribution().getShards(address);
logger.debugf("Shard for modification %s for address %s", shards, address);
return shards;
}
@Override
public boolean isOwnershipChanged(TopologyChangedEvent<?, ?> tce, String indeName) {
String shardId = indeName.substring(indeName.lastIndexOf('.') + 1);
ConsistentHash consistentHashAtStart = tce.getConsistentHashAtStart();
ConsistentHash consistentHashAtEnd = tce.getConsistentHashAtEnd();
ShardDistribution shardDistributionBefore = this.buildShardDistribution(consistentHashAtStart);
ShardDistribution shardDistributionAfter = this.buildShardDistribution(consistentHashAtEnd);
return !shardDistributionBefore.getOwner(shardId).equals(shardDistributionAfter.getOwner(shardId));
}
@TopologyChanged
@SuppressWarnings("unused")
public void onTopologyChange(TopologyChangedEvent<?, ?> tce) {
if (initialized) {
logger.debugf("Updating shard allocation");
this.shardDistribution = this.buildShardDistribution(distributionManager.getWriteConsistentHash());
}
}
}