package org.infinispan.counter.impl;
import java.util.EnumSet;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import org.infinispan.Cache;
import org.infinispan.commons.marshall.AdvancedExternalizer;
import org.infinispan.configuration.cache.CacheMode;
import org.infinispan.configuration.cache.Configuration;
import org.infinispan.configuration.cache.ConfigurationBuilder;
import org.infinispan.configuration.global.GlobalConfiguration;
import org.infinispan.counter.api.CounterConfiguration;
import org.infinispan.counter.api.CounterManager;
import org.infinispan.counter.api.CounterState;
import org.infinispan.counter.configuration.AbstractCounterConfiguration;
import org.infinispan.counter.configuration.CounterManagerConfiguration;
import org.infinispan.counter.configuration.CounterManagerConfigurationBuilder;
import org.infinispan.counter.configuration.Reliability;
import org.infinispan.counter.impl.entries.CounterKey;
import org.infinispan.counter.impl.entries.CounterValue;
import org.infinispan.counter.impl.function.AddFunction;
import org.infinispan.counter.impl.function.CompareAndSetFunction;
import org.infinispan.counter.impl.function.InitializeCounterFunction;
import org.infinispan.counter.impl.function.ReadFunction;
import org.infinispan.counter.impl.function.ResetFunction;
import org.infinispan.counter.impl.interceptor.CounterConfigurationInterceptor;
import org.infinispan.counter.impl.interceptor.CounterInterceptor;
import org.infinispan.counter.impl.listener.CounterFilterAndConvert;
import org.infinispan.counter.impl.manager.CacheHolder;
import org.infinispan.counter.impl.manager.EmbeddedCounterManager;
import org.infinispan.counter.impl.metadata.ConfigurationMetadata;
import org.infinispan.counter.impl.strong.StrongCounterKey;
import org.infinispan.counter.impl.weak.WeakCounterKey;
import org.infinispan.factories.GlobalComponentRegistry;
import org.infinispan.interceptors.impl.EntryWrappingInterceptor;
import org.infinispan.lifecycle.AbstractModuleLifecycle;
import org.infinispan.lifecycle.ModuleLifecycle;
import org.infinispan.manager.EmbeddedCacheManager;
import org.infinispan.registry.InternalCacheRegistry;
import org.infinispan.transaction.TransactionMode;
import org.kohsuke.MetaInfServices;
/**
* It register a {@link EmbeddedCounterManager} to each {@link EmbeddedCacheManager} started and starts the cache on it.
*
* @author Pedro Ruivo
* @since 9.0
*/
@MetaInfServices(value = ModuleLifecycle.class)
public class CounterModuleLifecycle extends AbstractModuleLifecycle {
public static final String COUNTER_CACHE_NAME = "___counters";
public static final String COUNTER_CONFIGURATION_CACHE_NAME = "___counter_configuration";
private static Configuration createCounterCacheConfiguration(CounterManagerConfiguration config) {
ConfigurationBuilder builder = new ConfigurationBuilder();
builder.clustering().cacheMode(CacheMode.DIST_SYNC)
.hash().numOwners(config.numOwners())
.stateTransfer().fetchInMemoryState(true)
.l1().disable()
.partitionHandling().enabled(config.reliability() == Reliability.CONSISTENT)
.transaction().transactionMode(TransactionMode.NON_TRANSACTIONAL)
.customInterceptors().addInterceptor().after(EntryWrappingInterceptor.class)
.interceptor(new CounterInterceptor());
return builder.build();
}
private static Configuration createCounterConfigurationCacheConfiguration() {
ConfigurationBuilder builder = new ConfigurationBuilder();
builder.clustering().cacheMode(CacheMode.REPL_SYNC)
.l1().disable()
.stateTransfer().fetchInMemoryState(true)
.partitionHandling().enabled(true)
.transaction().transactionMode(TransactionMode.NON_TRANSACTIONAL)
.customInterceptors().addInterceptor().after(EntryWrappingInterceptor.class)
.interceptor(new CounterConfigurationInterceptor());
return builder.build();
}
private static void addAdvancedExternalizer(Map<Integer, AdvancedExternalizer<?>> map, AdvancedExternalizer<?> ext) {
map.put(ext.getId(), ext);
}
private static CounterManagerConfiguration extractConfiguration(GlobalComponentRegistry globalComponentRegistry) {
CounterManagerConfiguration config = globalComponentRegistry.getGlobalConfiguration()
.module(CounterManagerConfiguration.class);
return config == null ? CounterManagerConfigurationBuilder.defaultConfiguration() : config;
}
private static void registerCounterManager(GlobalComponentRegistry registry, CompletableFuture<CacheHolder> future) {
//noinspection SynchronizationOnLocalVariableOrMethodParameter
synchronized (registry) {
CounterManager counterManager = registry.getComponent(CounterManager.class);
if (counterManager == null || !(counterManager instanceof EmbeddedCounterManager)) {
counterManager = new EmbeddedCounterManager(future,
registry.getGlobalConfiguration().globalState().enabled());
registry.registerComponent(counterManager, CounterManager.class);
}
}
}
private static void registerCounterCache(InternalCacheRegistry registry, CounterManagerConfiguration config) {
registry.registerInternalCache(COUNTER_CACHE_NAME, createCounterCacheConfiguration(config),
EnumSet.of(InternalCacheRegistry.Flag.EXCLUSIVE, InternalCacheRegistry.Flag.PERSISTENT));
}
private static void registerConfigurationCache(InternalCacheRegistry registry) {
registry.registerInternalCache(COUNTER_CONFIGURATION_CACHE_NAME, createCounterConfigurationCacheConfiguration(),
EnumSet.of(InternalCacheRegistry.Flag.EXCLUSIVE, InternalCacheRegistry.Flag.PERSISTENT));
}
private static CompletableFuture<CacheHolder> startCaches(EmbeddedCacheManager cacheManager,
List<AbstractCounterConfiguration> defaultCounters) {
final CompletableFuture<CacheHolder> future = new CompletableFuture<>();
new Thread(() -> {
try {
Cache<String, CounterConfiguration> configCache = cacheManager.getCache(COUNTER_CONFIGURATION_CACHE_NAME);
Cache<? extends CounterKey, CounterValue> counterCache = cacheManager.getCache(COUNTER_CACHE_NAME);
future.complete(
new CacheHolder(configCache.getAdvancedCache(), counterCache.getAdvancedCache(), defaultCounters));
} catch (Throwable throwable) {
future.completeExceptionally(throwable);
}
}).start();
return future;
}
@Override
public void cacheManagerStarting(GlobalComponentRegistry gcr, GlobalConfiguration globalConfiguration) {
final Map<Integer, AdvancedExternalizer<?>> externalizerMap = globalConfiguration.serialization()
.advancedExternalizers();
addAdvancedExternalizer(externalizerMap, ResetFunction.EXTERNALIZER);
addAdvancedExternalizer(externalizerMap, CounterFilterAndConvert.EXTERNALIZER);
addAdvancedExternalizer(externalizerMap, StrongCounterKey.EXTERNALIZER);
addAdvancedExternalizer(externalizerMap, WeakCounterKey.EXTERNALIZER);
addAdvancedExternalizer(externalizerMap, ReadFunction.EXTERNALIZER);
addAdvancedExternalizer(externalizerMap, CounterConfiguration.EXTERNALIZER);
addAdvancedExternalizer(externalizerMap, CounterValue.EXTERNALIZER);
addAdvancedExternalizer(externalizerMap, InitializeCounterFunction.EXTERNALIZER);
addAdvancedExternalizer(externalizerMap, ConfigurationMetadata.EXTERNALIZER);
addAdvancedExternalizer(externalizerMap, AddFunction.EXTERNALIZER);
addAdvancedExternalizer(externalizerMap, CompareAndSetFunction.EXTERNALIZER);
addAdvancedExternalizer(externalizerMap, CounterState.EXTERNALIZER);
}
@Override
public void cacheManagerStarted(GlobalComponentRegistry gcr) {
final EmbeddedCacheManager cacheManager = gcr.getComponent(EmbeddedCacheManager.class);
final InternalCacheRegistry internalCacheRegistry = gcr.getComponent(InternalCacheRegistry.class);
final CounterManagerConfiguration counterManagerConfiguration = extractConfiguration(gcr);
registerCounterCache(internalCacheRegistry, counterManagerConfiguration);
registerConfigurationCache(internalCacheRegistry);
CompletableFuture<CacheHolder> future = startCaches(cacheManager, counterManagerConfiguration.counters());
registerCounterManager(gcr, future);
}
}