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

org.infinispan.container.versioning.NumericVersionGenerator Maven / Gradle / Ivy

There is a newer version: 9.1.7.Final
Show newest version
package org.infinispan.container.versioning;

import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;

import org.infinispan.Cache;
import org.infinispan.factories.ComponentRegistry;
import org.infinispan.factories.annotations.Inject;
import org.infinispan.factories.annotations.Start;
import org.infinispan.notifications.Listener;
import org.infinispan.notifications.cachemanagerlistener.annotation.ViewChanged;
import org.infinispan.notifications.cachemanagerlistener.event.ViewChangedEvent;
import org.infinispan.remoting.transport.Address;
import org.infinispan.remoting.transport.Transport;
import org.infinispan.util.logging.Log;
import org.infinispan.util.logging.LogFactory;

/**
 * Generates unique numeric versions for both local and clustered environments.
 * When used on clustered caches, node information is used to guarantee versions
 * are unique cluster-wide.
 *
 * If the cache is configured to be local, the version generated is based
 * around an atomic counter. On the contrary, if the cache is clustered, the
 * generated version is composed of:
 * [view id (2 bytes)][rank (2 bytes)][version counter (4 bytes)], where rank
 * refers to the position of this node within the view.
 *
 * @author Galder Zamarreño
 * @since 5.3
 */
public class NumericVersionGenerator implements VersionGenerator {

   private static final Log log = LogFactory.getLog(NumericVersionGenerator.class);
   private static final boolean trace = log.isTraceEnabled();

   // TODO: Possibly seed version counter on capped System.currentTimeMillis, to avoid issues with clients holding to versions in between restarts
   final AtomicInteger versionCounter = new AtomicInteger();
   final AtomicLong versionPrefix = new AtomicLong();
   private static final NumericVersion NON_EXISTING = new NumericVersion(0);

   private Cache cache;
   private boolean isClustered;

   @Inject
   public void init(Cache cache) {
      this.cache = cache;
   }

   @Start(priority = 11) // after Transport
   public void start() {
      SecurityActions.addCacheManagerListener(cache.getCacheManager(), new RankCalculator());

      isClustered = SecurityActions.getCacheConfiguration(cache.getAdvancedCache()).clustering().cacheMode().isClustered();

      if (isClustered) {
         // Use component registry to avoid keeping an instance ref simply used on start
         ComponentRegistry componentRegistry = SecurityActions.getCacheComponentRegistry(cache.getAdvancedCache());
         Transport transport = componentRegistry
               .getGlobalComponentRegistry().getComponent(Transport.class);
         calculateRank(transport.getAddress(), transport.getMembers(), transport.getViewId());
      }
   }

   public NumericVersionGenerator clustered(boolean clustered) {
      isClustered = clustered;
      return this;
   }

   @Override
   public IncrementableEntryVersion generateNew() {
      long counter = versionCounter.incrementAndGet();
      return createNumericVersion(counter);

   }

   private IncrementableEntryVersion createNumericVersion(long counter) {
      // Version counter occupies the least significant 4 bytes of the version
      return isClustered
            ? new NumericVersion(versionPrefix.get() | counter)
            : new NumericVersion(counter);
   }

   @Override
   public IncrementableEntryVersion increment(IncrementableEntryVersion initialVersion) {
      if (initialVersion instanceof NumericVersion) {
         NumericVersion old = (NumericVersion) initialVersion;
         long counter = old.getVersion() + 1;
         return createNumericVersion(counter);
      }

      throw log.unexpectedInitialVersion(initialVersion.getClass().getName());
   }

   @Override
   public IncrementableEntryVersion nonExistingVersion() {
      return NON_EXISTING;
   }

   long calculateRank(Address address, List
members, long viewId) { long rank = findAddressRank(address, members, 1); // Version is composed of: // View id and rank form the prefix which is updated on a view change. long newVersionPrefix = (viewId << 48) | (rank << 32); // TODO: Deal with compareAndSet failures? versionPrefix.compareAndSet(versionPrefix.get(), newVersionPrefix); return versionPrefix.get(); } void resetCounter() { versionCounter.set(0); } private int findAddressRank(Address address, List
members, int rank) { if (address.equals(members.get(0))) return rank; else return findAddressRank(address, members.subList(1, members.size()), rank + 1); } @Listener public class RankCalculator { @ViewChanged @SuppressWarnings("unused") public void calculateRank(ViewChangedEvent e) { long rank = NumericVersionGenerator.this .calculateRank(e.getLocalAddress(), e.getNewMembers(), e.getViewId()); if (trace) log.tracef("Calculated rank based on view %s and result was %d", e, rank); } } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy