package org.infinispan.util;
import java.io.Serializable;
import java.util.List;
import java.util.Map;
import org.infinispan.commons.hash.Hash;
import org.infinispan.distribution.ch.ConsistentHashFactory;
import org.infinispan.distribution.ch.impl.ReplicatedConsistentHash;
import org.infinispan.marshall.core.ExternalPojo;
import org.infinispan.remoting.transport.Address;
/**
* ConsistentHashFactory implementation that allows the user to control who the owners are.
*
* @author Dan Berindei
* @since 7.0
*/
public class ReplicatedControlledConsistentHashFactory
implements ConsistentHashFactory<ReplicatedConsistentHash>, Serializable, ExternalPojo {
private volatile List<Address> membersToUse;
private int[] primaryOwnerIndices;
/**
* Create a consistent hash factory with a single segment.
*/
public ReplicatedControlledConsistentHashFactory(int primaryOwner1, int... otherPrimaryOwners) {
setOwnerIndexes(primaryOwner1, otherPrimaryOwners);
}
public void setOwnerIndexes(int primaryOwner1, int... otherPrimaryOwners) {
primaryOwnerIndices = concatOwners(primaryOwner1, otherPrimaryOwners);
}
@Override
public ReplicatedConsistentHash create(Hash hashFunction, int numOwners, int numSegments,
List<Address> members, Map<Address, Float> capacityFactors) {
int[] thePrimaryOwners = new int[primaryOwnerIndices.length];
for (int i = 0; i < primaryOwnerIndices.length; i++) {
if (membersToUse != null) {
int membersToUseIndex = Math.min(primaryOwnerIndices[i], membersToUse.size() - 1);
int membersIndex = members.indexOf(membersToUse.get(membersToUseIndex));
thePrimaryOwners[i] = membersIndex > 0 ? membersIndex : members.size() - 1;
} else {
thePrimaryOwners[i] = Math.min(primaryOwnerIndices[i], members.size() - 1);
}
}
return new ReplicatedConsistentHash(hashFunction, members, thePrimaryOwners);
}
@Override
public ReplicatedConsistentHash updateMembers(ReplicatedConsistentHash baseCH, List<Address> newMembers,
Map<Address, Float> capacityFactors) {
return create(baseCH.getHashFunction(), baseCH.getNumOwners(), baseCH.getNumSegments(), newMembers,
null);
}
@Override
public ReplicatedConsistentHash rebalance(ReplicatedConsistentHash baseCH) {
return create(baseCH.getHashFunction(), baseCH.getNumOwners(), baseCH.getNumSegments(),
baseCH.getMembers(), null);
}
@Override
public ReplicatedConsistentHash union(ReplicatedConsistentHash ch1, ReplicatedConsistentHash ch2) {
return ch1.union(ch2);
}
private int[] concatOwners(int head, int[] tail) {
int[] firstSegmentOwners;
if (tail == null || tail.length == 0) {
firstSegmentOwners = new int[]{head};
} else {
firstSegmentOwners = new int[tail.length + 1];
firstSegmentOwners[0] = head;
for (int i = 0; i < tail.length; i++) {
firstSegmentOwners[i + 1] = tail[i];
}
}
return firstSegmentOwners;
}
/**
* @param membersToUse Owner indexes will be in this list, instead of the current list of members
*/
public void setMembersToUse(List<Address> membersToUse) {
this.membersToUse = membersToUse;
}
}