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

org.infinispan.distribution.LocalizedCacheTopology Maven / Gradle / Ivy

There is a newer version: 15.1.0.Dev04
Show newest version
package org.infinispan.distribution;

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 org.infinispan.commons.util.ImmutableHopscotchHashSet;
import org.infinispan.commons.util.IntSet;
import org.infinispan.commons.util.IntSets;
import org.infinispan.configuration.cache.CacheMode;
import org.infinispan.distribution.ch.ConsistentHash;
import org.infinispan.distribution.ch.KeyPartitioner;
import org.infinispan.distribution.ch.impl.SingleSegmentKeyPartitioner;
import org.infinispan.remoting.transport.Address;
import org.infinispan.topology.CacheTopology;

/**
 * Extends {@link CacheTopology} with information about keys owned by the local node.
 *
 * @author Dan Berindei
 * @since 9.0
 */
public class LocalizedCacheTopology extends CacheTopology {

   private final Address localAddress;
   private boolean connected;
   private final Set
membersSet; private final KeyPartitioner keyPartitioner; private final boolean isDistributed; private final boolean allLocal; private final int numSegments; private final int maxOwners; private final DistributionInfo[] distributionInfos; /** * @param cacheMode Ignored, the result topology is always LOCAL * @param localAddress Address of the local node */ public static LocalizedCacheTopology makeSingletonTopology(CacheMode cacheMode, Address localAddress) { List
members = Collections.singletonList(localAddress); CacheTopology cacheTopology = new CacheTopology(-1, -1, null, null, Phase.NO_REBALANCE, members, null); return new LocalizedCacheTopology(CacheMode.LOCAL, cacheTopology, SingleSegmentKeyPartitioner.getInstance(), localAddress, false); } /** * Creates a new local topology that has a single address but multiple segments. This is useful when the data * storage is segmented in some way (ie. segmented store) * @param keyPartitioner partitioner to decide which segment a given key maps to * @param numSegments how many segments there are * @param localAddress the address of this node * @return segmented topology */ public static LocalizedCacheTopology makeSegmentedSingletonTopology(KeyPartitioner keyPartitioner, int numSegments, Address localAddress) { return new LocalizedCacheTopology(keyPartitioner, numSegments, localAddress); } public LocalizedCacheTopology(CacheMode cacheMode, CacheTopology cacheTopology, KeyPartitioner keyPartitioner, Address localAddress, boolean connected) { super(cacheTopology.getTopologyId(), cacheTopology.getRebalanceId(), cacheTopology.getCurrentCH(), cacheTopology.getPendingCH(), cacheTopology.getUnionCH(), cacheTopology.getPhase(), cacheTopology.getActualMembers(), cacheTopology.getMembersPersistentUUIDs()); ConsistentHash readCH = getReadConsistentHash(); ConsistentHash writeCH = getWriteConsistentHash(); this.localAddress = localAddress; this.connected = connected; this.membersSet = new ImmutableHopscotchHashSet<>(cacheTopology.getMembers()); this.keyPartitioner = keyPartitioner; this.isDistributed = cacheMode.isDistributed(); boolean isReplicated = cacheMode.isReplicated(); boolean isInvalidation = cacheMode.isInvalidation(); if (isDistributed) { this.numSegments = readCH.getNumSegments(); this.distributionInfos = new DistributionInfo[numSegments]; int maxOwners = 1; for (int segmentId = 0; segmentId < numSegments; segmentId++) { Address primary = readCH.locatePrimaryOwnerForSegment(segmentId); List
readOwners = readCH.locateOwnersForSegment(segmentId); List
writeOwners = writeCH.locateOwnersForSegment(segmentId); Collection
writeBackups = writeOwners.subList(1, writeOwners.size()); this.distributionInfos[segmentId] = new DistributionInfo(segmentId, primary, readOwners, writeOwners, writeBackups, localAddress); maxOwners = Math.max(maxOwners, writeOwners.size()); } this.maxOwners = maxOwners; this.allLocal = false; } else if (isReplicated || isInvalidation) { this.numSegments = readCH.getNumSegments(); // Writes/invalidations must be broadcast to the entire cluster Map> readOwnersMap = new HashMap<>(); Map> writeOwnersMap = new HashMap<>(); this.distributionInfos = new DistributionInfo[numSegments]; for (int segmentId = 0; segmentId < numSegments; segmentId++) { int segmentCopy = segmentId; Address primary = readCH.locatePrimaryOwnerForSegment(segmentId); List
readOwners = readOwnersMap.computeIfAbsent(primary, p -> List.copyOf(readCH.locateOwnersForSegment(segmentCopy))); List
writeOwners = writeOwnersMap.computeIfAbsent(primary, p -> List.copyOf(writeCH.locateOwnersForSegment(segmentCopy))); List
writeBackups = writeOwners.subList(1, writeOwners.size()); this.distributionInfos[segmentId] = new DistributionInfo(segmentId, primary, readOwners, writeOwners, writeBackups, localAddress); } this.maxOwners = cacheTopology.getMembers().size(); this.allLocal = readOwnersMap.containsKey(localAddress); } else { assert cacheMode == CacheMode.LOCAL; this.numSegments = 1; List
owners = Collections.singletonList(localAddress); List
writeBackups = Collections.emptyList(); this.distributionInfos = new DistributionInfo[]{ new DistributionInfo(0, localAddress, owners, owners, writeBackups, localAddress) }; this.maxOwners = 1; this.allLocal = true; } } private LocalizedCacheTopology(KeyPartitioner keyPartitioner, int numSegments, Address localAddress) { super(-1, -1, null, null, null, Collections.singletonList(localAddress), null); this.localAddress = localAddress; this.numSegments = numSegments; this.keyPartitioner = keyPartitioner; this.membersSet = Collections.singleton(localAddress); this.isDistributed = false; // Reads and writes are local, only the invalidation is replicated List
owners = Collections.singletonList(localAddress); this.distributionInfos = new DistributionInfo[numSegments]; for (int i = 0; i < distributionInfos.length; ++i) { distributionInfos[i] = new DistributionInfo(i, localAddress, owners, owners, Collections.emptyList(), localAddress); } this.maxOwners = 1; this.allLocal = true; } /** * @return {@code true} iff key {@code key} can be read without going remote. */ public boolean isReadOwner(Object key) { if (allLocal) return true; int segmentId = keyPartitioner.getSegment(key); return distributionInfos[segmentId].isReadOwner(); } public boolean isSegmentReadOwner(int segment) { return allLocal || distributionInfos[segment].isReadOwner(); } /** * @return {@code true} iff writing a value for key {@code key} will update it on the local node. */ public boolean isWriteOwner(Object key) { if (allLocal) return true; int segmentId = keyPartitioner.getSegment(key); return distributionInfos[segmentId].isWriteOwner(); } public boolean isSegmentWriteOwner(int segment) { return allLocal || distributionInfos[segment].isWriteOwner(); } /** * @return The consistent hash segment of key {@code key} */ public int getSegment(Object key) { return keyPartitioner.getSegment(key); } public DistributionInfo getSegmentDistribution(int segmentId) { return distributionInfos[segmentId]; } /** * @return Information about the ownership of key {@code key}, including the primary owner. */ public DistributionInfo getDistribution(Object key) { int segmentId = keyPartitioner.getSegment(key); return distributionInfos[segmentId]; } /** * @return An unordered collection with the write owners of {@code key}. */ public Collection
getWriteOwners(Object key) { int segmentId = isDistributed ? keyPartitioner.getSegment(key) : 0; return distributionInfos[segmentId].writeOwners(); } /** * @return An unordered collection with the write owners of {@code keys}. */ public Collection
getWriteOwners(Collection keys) { if (keys.isEmpty()) { return Collections.emptySet(); } if (isDistributed) { if (keys.size() == 1) { Object singleKey = keys.iterator().next(); return getDistribution(singleKey).writeOwners(); } else { IntSet segments = IntSets.mutableEmptySet(numSegments); // Expecting some overlap between keys Set
owners = new HashSet<>(2 * maxOwners); for (Object key : keys) { int segment = keyPartitioner.getSegment(key); if (segments.add(segment)) { owners.addAll(getSegmentDistribution(segment).writeOwners()); } } return owners; } } else { return getSegmentDistribution(0).writeOwners(); } } /** * @return The segments owned by the local node for reading. */ public IntSet getLocalReadSegments() { if (isDistributed) { IntSet localSegments = IntSets.mutableEmptySet(numSegments); for (int segment = 0; segment < numSegments; segment++) { if (distributionInfos[segment].isReadOwner()) { localSegments.set(segment); } } return localSegments; } else if (allLocal) { return IntSets.immutableRangeSet(numSegments); } else { return IntSets.immutableEmptySet(); } } /** * @return The segments owned by the local node for writing. */ public IntSet getLocalWriteSegments() { if (isDistributed) { IntSet localSegments = IntSets.mutableEmptySet(numSegments); for (int segmentId = 0; segmentId < numSegments; segmentId++) { if (distributionInfos[segmentId].isWriteOwner()) { localSegments.set(segmentId); } } return localSegments; } else if (allLocal) { return IntSets.immutableRangeSet(numSegments); } else { return IntSets.immutableEmptySet(); } } /** * @return The segments owned by the local node as primary owner. */ public IntSet getLocalPrimarySegments() { if (membersSet.size() > 1) { IntSet localSegments = IntSets.mutableEmptySet(numSegments); for (int segment = 0; segment < numSegments; segment++) { if (distributionInfos[segment].isPrimary()) { localSegments.set(segment); } } return localSegments; } else { return IntSets.immutableRangeSet(numSegments); } } /** * @return The number of segments owned by the local node for writing. */ public int getLocalWriteSegmentsCount() { if (isDistributed) { int count = 0; for (int segment = 0; segment < numSegments; segment++) { if (distributionInfos[segment].isWriteOwner()) { count++; } } return count; } else if (allLocal) { return numSegments; } else { return 0; } } /** * @return The address of the local node. */ public Address getLocalAddress() { return localAddress; } public Set
getMembersSet() { return membersSet; } /** * @return {@code true} if the local node received this topology from the coordinator, * {@code false} otherwise (e.g. during preload). */ public boolean isConnected() { return connected; } public int getNumSegments() { return numSegments; } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy