All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.infinispan.distribution.ch.impl.AbstractConsistentHash Maven / Gradle / Ivy

There is a newer version: 9.1.7.Final
Show newest version
package org.infinispan.distribution.ch.impl;

import org.infinispan.commons.hash.Hash;
import org.infinispan.commons.util.Util;
import org.infinispan.distribution.ch.ConsistentHash;
import org.infinispan.globalstate.ScopedPersistentState;
import org.infinispan.remoting.transport.Address;
import org.infinispan.topology.PersistentUUID;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.function.UnaryOperator;

/**
 * @author Radim Vansa <[email protected]>
 */
public abstract class AbstractConsistentHash implements ConsistentHash {
   // State constants
   protected static final String STATE_CAPACITY_FACTOR = "capacityFactor.%d";
   protected static final String STATE_CAPACITY_FACTORS = "capacityFactors";
   protected static final String STATE_NUM_SEGMENTS = "numSegments";

   protected final Hash hashFunction;
   /**
    * The membership of the cache topology that uses this CH.
    */
   protected final List
members; protected final float[] capacityFactors; protected final int segmentSize; protected AbstractConsistentHash(Hash hashFunction, int numSegments, List
members, Map capacityFactors) { if (numSegments < 1) throw new IllegalArgumentException("The number of segments must be strictly positive"); this.hashFunction = hashFunction; this.members = new ArrayList<>(members); if (capacityFactors == null) { this.capacityFactors = null; } else { this.capacityFactors = new float[members.size()]; for (int i = 0; i < this.capacityFactors.length; i++) { this.capacityFactors[i] = capacityFactors.get(members.get(i)); } } this.segmentSize = Util.getSegmentSize(numSegments); } protected AbstractConsistentHash(Hash hashFunction, int numSegments, List
members, float[] capacityFactors) { if (numSegments < 1) throw new IllegalArgumentException("The number of segments must be strictly positive"); this.hashFunction = hashFunction; this.members = members; this.capacityFactors = capacityFactors; this.segmentSize = Util.getSegmentSize(numSegments); } protected AbstractConsistentHash(ScopedPersistentState state) { this(parseHashFunction(state), parseNumSegments(state), parseMembers(state), parseCapacityFactors(state)); } protected static int parseNumSegments(ScopedPersistentState state) { return state.getIntProperty(STATE_NUM_SEGMENTS); } protected static List
parseMembers(ScopedPersistentState state) { int numMembers = Integer.parseInt(state.getProperty(ConsistentHashPersistenceConstants.STATE_MEMBERS)); List
members = new ArrayList<>(numMembers); for(int i = 0; i < numMembers; i++) { PersistentUUID uuid = PersistentUUID.fromString(state.getProperty(String.format(ConsistentHashPersistenceConstants.STATE_MEMBER, i))); members.add(uuid); } return members; } protected static Hash parseHashFunction(ScopedPersistentState state) { return Util.getInstance(state.getProperty(ConsistentHashPersistenceConstants.STATE_HASH_FUNCTION), null); } protected static float[] parseCapacityFactors(ScopedPersistentState state) { int numCapacityFactors = Integer.parseInt(state.getProperty(STATE_CAPACITY_FACTORS)); float[] capacityFactors = new float[numCapacityFactors]; for (int i = 0; i < numCapacityFactors; i++) { capacityFactors[i] = Float.parseFloat(state.getProperty(String.format(STATE_CAPACITY_FACTOR, i))); } return capacityFactors; } @Override public void toScopedState(ScopedPersistentState state) { state.setProperty(ConsistentHashPersistenceConstants.STATE_CONSISTENT_HASH, this.getClass().getName()); state.setProperty(STATE_NUM_SEGMENTS, getNumSegments()); state.setProperty(ConsistentHashPersistenceConstants.STATE_MEMBERS, members.size()); for (int i = 0; i < members.size(); i++) { state.setProperty(String.format(ConsistentHashPersistenceConstants.STATE_MEMBER, i), members.get(i).toString()); } state.setProperty(STATE_CAPACITY_FACTORS, capacityFactors.length); for (int i = 0; i < capacityFactors.length; i++) { state.setProperty(String.format(STATE_CAPACITY_FACTOR, i), capacityFactors[i]); } state.setProperty(ConsistentHashPersistenceConstants.STATE_HASH_FUNCTION, hashFunction.getClass().getName()); } @Override public Hash getHashFunction() { return hashFunction; } @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; } @Override public List
getMembers() { return members; } @Override public boolean isKeyLocalToNode(Address nodeAddress, Object key) { return isSegmentLocalToNode(nodeAddress, getSegment(key)); } /** * Adds all elements from src list that do not already exist in dest list to the latter. * * @param dest List where elements are added * @param src List of elements to add - this is never modified */ protected static void mergeLists(List
dest, List
src) { for (Address node : src) { if (!dest.contains(node)) { dest.add(node); } } } static HashMap getMemberIndexMap(List
members) { HashMap memberIndexes = new HashMap<>(members.size()); for (int i = 0; i < members.size(); i++) { memberIndexes.put(members.get(i), i); } return memberIndexes; } public Map getCapacityFactors() { if (capacityFactors == null) return null; Map capacityFactorsMap = new HashMap<>(members.size()); for (int i = 0; i < members.size(); i++) { capacityFactorsMap.put(members.get(i), capacityFactors[i]); } return capacityFactorsMap; } protected Map unionCapacityFactors(AbstractConsistentHash ch2) { Map unionCapacityFactors = null; if (this.capacityFactors != null || ch2.capacityFactors != null) { unionCapacityFactors = new HashMap<>(); if (this.capacityFactors != null) { unionCapacityFactors.putAll(this.getCapacityFactors()); } else { for (Address node : this.members) { unionCapacityFactors.put(node, 1.0f); } } if (ch2.capacityFactors != null) { unionCapacityFactors.putAll(ch2.getCapacityFactors()); } else { for (Address node : ch2.members) { unionCapacityFactors.put(node, 1.0f); } } } return unionCapacityFactors; } protected void checkSameHashAndSegments(AbstractConsistentHash dch2) { if (!hashFunction.equals(dch2.getHashFunction())) { throw new IllegalArgumentException("The consistent hash objects must have the same hash function"); } int numSegments = getNumSegments(); if (numSegments != dch2.getNumSegments()) { throw new IllegalArgumentException("The consistent hash objects must have the same number of segments"); } } protected Map remapCapacityFactors(UnaryOperator
remapper) { Map remappedCapacityFactors = null; if (capacityFactors != null) { remappedCapacityFactors = new HashMap<>(members.size()); for(int i=0; i < members.size(); i++) { remappedCapacityFactors.put(remapper.apply(members.get(i)), capacityFactors[i]); } } return remappedCapacityFactors; } protected List
remapMembers(UnaryOperator
remapper) { List
remappedMembers = new ArrayList<>(members.size()); for(Iterator
i = members.iterator(); i.hasNext(); ) { Address a = remapper.apply(i.next()); if (a == null) { return null; } remappedMembers.add(a); } return remappedMembers; } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy