
org.infinispan.distribution.ch.impl.DefaultConsistentHash Maven / Gradle / Ivy
package org.infinispan.distribution.ch.impl;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import net.jcip.annotations.Immutable;
import org.infinispan.commons.hash.Hash;
import org.infinispan.commons.marshall.AbstractExternalizer;
import org.infinispan.commons.marshall.InstanceReusingAdvancedExternalizer;
import org.infinispan.commons.util.Immutables;
import org.infinispan.commons.util.Util;
import org.infinispan.distribution.ch.ConsistentHash;
import org.infinispan.marshall.core.Ids;
import org.infinispan.remoting.transport.Address;
/**
* Default {@link ConsistentHash} implementation. This object is immutable.
*
* @author Dan Berindei
* @author [email protected]
* @since 5.2
*/
@Immutable
public class DefaultConsistentHash implements ConsistentHash {
private final Hash hashFunction;
private final int numOwners;
private final int numSegments;
/**
* The membership of the cache topology that uses this CH.
*/
private final List members;
private Map capacityFactors;
/**
* The routing table.
*/
private final List[] segmentOwners;
private final int segmentSize;
public DefaultConsistentHash(Hash hashFunction, int numOwners, int numSegments, List members,
Map capacityFactors, List[] segmentOwners) {
if (numSegments < 1)
throw new IllegalArgumentException("The number of segments must be strictly positive");
if (numOwners < 1)
throw new IllegalArgumentException("The number of owners must be strictly positive");
this.numOwners = numOwners;
this.numSegments = numSegments;
this.hashFunction = hashFunction;
this.members = new ArrayList(members);
this.capacityFactors = capacityFactors != null ? new HashMap(capacityFactors) : null;
this.segmentOwners = new List[numSegments];
for (int i = 0; i < numSegments; i++) {
if (segmentOwners[i] == null || segmentOwners[i].isEmpty()) {
throw new IllegalArgumentException("Segment owner list cannot be null or empty");
}
this.segmentOwners[i] = Immutables.immutableListCopy(segmentOwners[i]);
}
this.segmentSize = Util.getSegmentSize(numSegments);
}
@Override
public Hash getHashFunction() {
return hashFunction;
}
@Override
public int getNumSegments() {
return numSegments;
}
@Override
public Set getSegmentsForOwner(Address owner) {
if (owner == null) {
throw new IllegalArgumentException("owner cannot be null");
}
if (!members.contains(owner)) {
throw new IllegalArgumentException("Node " + owner + " is not a member");
}
Set segments = new HashSet();
for (int segment = 0; segment < segmentOwners.length; segment++) {
if (segmentOwners[segment].contains(owner)) {
segments.add(segment);
}
}
return segments;
}
@Override
public Set getPrimarySegmentsForOwner(Address owner) {
if (owner == null) {
throw new IllegalArgumentException("owner cannot be null");
}
if (!members.contains(owner)) {
throw new IllegalArgumentException("Node " + owner + " is not a member");
}
Set segments = new HashSet();
for (int segment = 0; segment < segmentOwners.length; segment++) {
if (owner.equals(segmentOwners[segment].get(0))) {
segments.add(segment);
}
}
return segments;
}
@Override
public int getSegment(Object key) {
// The result must always be positive, so we make sure the dividend is positive first
return getNormalizedHash(key) / segmentSize;
}
public int getNormalizedHash(Object key) {
return hashFunction.hash(key) & Integer.MAX_VALUE;
}
public List getSegmentEndHashes() {
List hashes = new ArrayList(numSegments);
for (int i = 0; i < numSegments; i++) {
hashes.add(((i + 1) % numSegments) * segmentSize);
}
return hashes;
}
@Override
public List locateOwnersForSegment(int segmentId) {
return segmentOwners[segmentId];
}
@Override
public Address locatePrimaryOwnerForSegment(int segmentId) {
return segmentOwners[segmentId].get(0);
}
@Override
public List getMembers() {
return members;
}
@Override
public int getNumOwners() {
return numOwners;
}
@Override
public Address locatePrimaryOwner(Object key) {
return locatePrimaryOwnerForSegment(getSegment(key));
}
@Override
public List locateOwners(Object key) {
return locateOwnersForSegment(getSegment(key));
}
@Override
public Set locateAllOwners(Collection
© 2015 - 2025 Weber Informatics LLC | Privacy Policy