package org.infinispan.util; import static org.testng.AssertJUnit.assertEquals; import java.io.Serializable; import java.util.ArrayList; 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.DefaultConsistentHash; import org.infinispan.marshall.core.ExternalPojo; import org.infinispan.remoting.transport.Address; /** * Base consistent hash factory that contains a single segments * * @author Pedro Ruivo * @since 6.0 */ @SuppressWarnings("unchecked") public abstract class BaseControlledConsistentHashFactory implements ConsistentHashFactory<DefaultConsistentHash>, Serializable, ExternalPojo { protected final int numSegments; protected BaseControlledConsistentHashFactory(int numSegments) { this.numSegments = numSegments; } @Override public DefaultConsistentHash create(Hash hashFunction, int numOwners, int numSegments, List<Address> members, Map<Address, Float> capacityFactors) { assertNumberOfSegments(numSegments); List<Address>[] segmentOwners = new List[numSegments]; for (int i = 0; i < numSegments; i++) { segmentOwners[i] = createOwnersCollection(members, numOwners, i); } return new DefaultConsistentHash(hashFunction, numOwners, numSegments, members, null, segmentOwners); } @Override public DefaultConsistentHash updateMembers(DefaultConsistentHash baseCH, List<Address> newMembers, Map<Address, Float> capacityFactors) { assertNumberOfSegments(baseCH.getNumSegments()); final int numOwners = baseCH.getNumOwners(); List<Address>[] segmentOwners = new List[numSegments]; for (int i = 0; i < numSegments; i++) { List<Address> owners = new ArrayList<Address>(baseCH.locateOwnersForSegment(i)); owners.retainAll(newMembers); if (owners.isEmpty()) { // updateMembers should only add new owners if there are no owners left owners = createOwnersCollection(newMembers, numOwners, i); } segmentOwners[i] = owners; } DefaultConsistentHash updated = new DefaultConsistentHash(baseCH.getHashFunction(), numOwners, numSegments, newMembers, null, segmentOwners); return baseCH.equals(updated) ? baseCH : updated; } @Override public DefaultConsistentHash rebalance(DefaultConsistentHash baseCH) { DefaultConsistentHash rebalanced = create(baseCH.getHashFunction(), baseCH.getNumOwners(), baseCH.getNumSegments(), baseCH.getMembers(), baseCH.getCapacityFactors()); return baseCH.equals(rebalanced) ? baseCH : rebalanced; } @Override public DefaultConsistentHash union(DefaultConsistentHash ch1, DefaultConsistentHash ch2) { assertNumberOfSegments(ch1.getNumSegments()); assertNumberOfSegments(ch2.getNumSegments()); return ch1.union(ch2); } protected abstract List<Address> createOwnersCollection(List<Address> members, int numberOfOwners, int segmentIndex); private void assertNumberOfSegments(int numSegments) { assertEquals("Wrong number of segments.", this.numSegments, numSegments); } }