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

org.infinispan.client.hotrod.impl.TopologyInfo Maven / Gradle / Ivy

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

import org.infinispan.client.hotrod.CacheTopologyInfo;
import org.infinispan.client.hotrod.configuration.Configuration;
import org.infinispan.client.hotrod.impl.consistenthash.ConsistentHash;
import org.infinispan.client.hotrod.impl.consistenthash.ConsistentHashFactory;
import org.infinispan.client.hotrod.impl.consistenthash.SegmentConsistentHash;
import org.infinispan.client.hotrod.impl.protocol.HotRodConstants;
import org.infinispan.client.hotrod.logging.Log;
import org.infinispan.client.hotrod.logging.LogFactory;
import org.infinispan.commons.equivalence.AnyEquivalence;
import org.infinispan.commons.equivalence.ByteArrayEquivalence;
import org.infinispan.commons.util.CollectionFactory;
import org.infinispan.commons.util.Immutables;

import java.net.SocketAddress;
import java.util.Collection;
import java.util.Collections;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

import static java.util.function.Function.identity;
import static java.util.stream.Collectors.toMap;
import static java.util.stream.IntStream.range;

/**
 * Maintains topology information about caches.
 *
 * @author gustavonalle
 */
public final class TopologyInfo {

   private static final Log log = LogFactory.getLog(TopologyInfo.class, Log.class);
   private static final boolean trace = log.isTraceEnabled();
   private static final byte[] EMPTY_BYTES = new byte[0];

   private Map> servers = CollectionFactory.makeMap(ByteArrayEquivalence.INSTANCE, AnyEquivalence.getInstance());
   private Map consistentHashes = CollectionFactory.makeMap(ByteArrayEquivalence.INSTANCE, AnyEquivalence.getInstance());
   private Map segmentsByCache = CollectionFactory.makeMap(ByteArrayEquivalence.INSTANCE, AnyEquivalence.getInstance());
   private Map topologyIds = CollectionFactory.makeMap(ByteArrayEquivalence.INSTANCE, AnyEquivalence.getInstance());
   private final ConsistentHashFactory hashFactory = new ConsistentHashFactory();

   public TopologyInfo(AtomicInteger topologyId, Collection initialServers, Configuration configuration) {
      this.topologyIds.put(EMPTY_BYTES, topologyId);
      this.servers.put(EMPTY_BYTES, initialServers);
      this.hashFactory.init(configuration);
   }

   private Map> getSegmentsByServer(byte[] cacheName) {
      ConsistentHash consistentHash = consistentHashes.get(cacheName);
      if (consistentHash != null) {
         return consistentHash.getSegmentsByServer();
      } else {
         Optional numSegments = Optional.ofNullable(segmentsByCache.get(cacheName));
         Optional> segments = numSegments.map(n -> range(0, n).boxed().collect(Collectors.toSet()));
         return Immutables.immutableMapWrap(
               servers.get(cacheName).stream().collect(toMap(identity(), s -> segments.orElse(Collections.emptySet())))
         );
      }
   }

   public Collection getServers(byte[] cacheName) {
      return servers.computeIfAbsent(cacheName, k -> servers.get(EMPTY_BYTES));
   }

   public Collection getServers() {
      return servers.values().stream().flatMap(Collection::stream).collect(Collectors.toList());
   }

   public void updateTopology(Map> servers2Hash, int numKeyOwners, short hashFunctionVersion, int hashSpace,
         byte[] cacheName, AtomicInteger topologyId) {
      ConsistentHash hash = hashFactory.newConsistentHash(hashFunctionVersion);
      if (hash == null) {
         log.noHasHFunctionConfigured(hashFunctionVersion);
      } else {
         hash.init(servers2Hash, numKeyOwners, hashSpace);
      }
      consistentHashes.put(cacheName, hash);
      topologyIds.put(cacheName, topologyId);
   }

   public void updateTopology(SocketAddress[][] segmentOwners, int numSegments, short hashFunctionVersion,
         byte[] cacheName, AtomicInteger topologyId) {
      if (hashFunctionVersion > 0) {
         SegmentConsistentHash hash = hashFactory.newConsistentHash(hashFunctionVersion);
         if (hash == null) {
            log.noHasHFunctionConfigured(hashFunctionVersion);
         } else {
            hash.init(segmentOwners, numSegments);
         }
         consistentHashes.put(cacheName, hash);
      }
      segmentsByCache.put(cacheName, numSegments);
      topologyIds.put(cacheName, topologyId);
   }

   public Optional getHashAwareServer(Object key, byte[] cacheName) {
      Optional server = Optional.empty();
      if (isTopologyValid(cacheName)) {
         ConsistentHash consistentHash = consistentHashes.get(cacheName);
         if (consistentHash != null) {
            server = Optional.of(consistentHash.getServer(key));
            if (trace) {
               log.tracef("Using consistent hash for determining the server: " + server);
            }
         }
         return server;
      }

      return Optional.empty();
   }

   public boolean isTopologyValid(byte[] cacheName) {
      Integer id = topologyIds.get(cacheName).get();
      Boolean valid = id != HotRodConstants.SWITCH_CLUSTER_TOPOLOGY;
      if (trace)
         log.tracef("Is topology id (%s) valid? %b", id, valid);

      return valid;
   }

   public void updateServers(byte[] cacheName, Collection updatedServers) {
      if (cacheName == null || cacheName.length == 0) {
         servers.keySet().forEach(k -> servers.put(k, updatedServers));
      } else {
         servers.put(cacheName, updatedServers);
      }
   }


   public ConsistentHash getConsistentHash(byte[] cacheName) {
      return consistentHashes.get(cacheName);
   }

   public ConsistentHashFactory getConsistentHashFactory() {
      return hashFactory;
   }

   public AtomicInteger createTopologyId(byte[] cacheName, int topologyId) {
      AtomicInteger id = new AtomicInteger(topologyId);
      this.topologyIds.put(cacheName, id);
      return id;
   }

   public void setTopologyId(byte[] cacheName, int topologyId) {
      AtomicInteger id = this.topologyIds.get(cacheName);
      id.set(topologyId);
   }

   public void setAllTopologyIds(int newTopologyId) {
      for (AtomicInteger topologyId : topologyIds.values())
         topologyId.set(newTopologyId);
   }

   public int getTopologyId(byte[] cacheName)  {
      return topologyIds.get(cacheName).get();
   }

   public CacheTopologyInfo getCacheTopologyInfo(byte[] cacheName) {
      return new CacheTopologyInfoImpl(getSegmentsByServer(cacheName), segmentsByCache.get(cacheName),
         topologyIds.get(cacheName).get());
   }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy