package org.infinispan.query.affinity; import java.io.Serializable; import java.util.Collections; import java.util.Properties; import java.util.Set; import org.apache.lucene.document.Document; import org.hibernate.search.engine.service.spi.ServiceManager; import org.hibernate.search.filter.FullTextFilterImplementor; import org.hibernate.search.spi.BuildContext; import org.hibernate.search.store.ShardIdentifierProvider; import org.infinispan.commons.logging.LogFactory; import org.infinispan.configuration.cache.ClusteringConfiguration; import org.infinispan.distribution.DistributionManager; import org.infinispan.factories.ComponentRegistry; import org.infinispan.hibernate.search.spi.CacheManagerService; import org.infinispan.manager.EmbeddedCacheManager; import org.infinispan.query.backend.ComponentRegistryService; import org.infinispan.query.backend.KeyTransformationHandler; import org.infinispan.query.backend.QueryInterceptor; import org.infinispan.query.logging.Log; import org.infinispan.remoting.rpc.RpcManager; import org.infinispan.remoting.transport.Address; import org.infinispan.remoting.transport.LocalModeAddress; /** * Dynamic sharding based on the segment associated with the key * * @author gustavonalle * @since 8.2 */ public class AffinityShardIdentifierProvider implements ShardIdentifierProvider { private static final Log log = LogFactory.getLog(AffinityShardIdentifierProvider.class, Log.class); private static final String NUMBER_OF_SHARDS_PROP = "nbr_of_shards"; // these are lazily initialized from ComponentRegistry private RpcManager rpcManager; private DistributionManager distributionManager; private KeyTransformationHandler keyTransformationHandler; private ComponentRegistry componentRegistry; private ShardAllocatorManager shardAllocatorManager; @Override public void initialize(Properties properties, BuildContext buildContext) { ServiceManager serviceManager = buildContext.getServiceManager(); ComponentRegistryService componentRegistryService = serviceManager.requestService(ComponentRegistryService.class); this.componentRegistry = componentRegistryService.getComponentRegistry(); CacheManagerService cacheManagerService = serviceManager.requestService(CacheManagerService.class); EmbeddedCacheManager embeddedCacheManager = cacheManagerService.getEmbeddedCacheManager(); rpcManager = componentRegistry.getComponent(RpcManager.class); String cacheName = componentRegistry.getCacheName(); ClusteringConfiguration clusteringConfiguration = embeddedCacheManager.getCacheConfiguration(cacheName).clustering(); Integer numberOfShards = getNumberOfShards(properties); shardAllocatorManager = this.componentRegistry.getComponent(ShardAllocatorManager.class); shardAllocatorManager.initialize(numberOfShards, clusteringConfiguration.hash().numSegments()); if (log.isDebugEnabled()) { log.debugf("Initializing ShardIdProvider with %d shards", numberOfShards); } } private int getSegment(Object key) { DistributionManager distributionManager = this.getDistributionManager(); if (distributionManager == null) { return 0; } return distributionManager.getCacheTopology().getSegment(key); } @Override public String getShardIdentifier(Class<?> entityType, Serializable id, String idAsString, Document document) { Object key = this.getKeyTransformationHandler().stringToKey(idAsString, null); int segment = this.getSegment(key); String shardId = shardAllocatorManager.getShardFromSegment(segment); if (log.isDebugEnabled()) { log.debugf("Shard Identifier for segment[%s] = %s mapped to shard %s", id, segment, shardId); } return shardId; } @Override public Set<String> getShardIdentifiersForQuery(FullTextFilterImplementor[] fullTextFilters) { return shardAllocatorManager.getShards(); } @Override public Set<String> getShardIdentifiersForDeletion(Class<?> entity, Serializable id, String idInString) { Address address = rpcManager != null ? rpcManager.getAddress() : LocalModeAddress.INSTANCE; Set<String> shardsForModification = shardAllocatorManager.getShardsForModification(address); if (shardsForModification == null) return Collections.emptySet(); if (log.isDebugEnabled()) { log.debugf("Shard for modification, [%d] %s", shardsForModification.size(), shardsForModification); } return shardsForModification; } @Override public Set<String> getAllShardIdentifiers() { return shardAllocatorManager.getShards(); } private KeyTransformationHandler getKeyTransformationHandler() { if (keyTransformationHandler == null) { keyTransformationHandler = componentRegistry.getComponent(QueryInterceptor.class) .getKeyTransformationHandler(); } return keyTransformationHandler; } private DistributionManager getDistributionManager() { if (distributionManager == null) { distributionManager = componentRegistry.getComponent(DistributionManager.class); } return distributionManager; } private static Integer getNumberOfShards(Properties properties) { String nShards = properties.getProperty(NUMBER_OF_SHARDS_PROP); return nShards != null ? Integer.valueOf(nShards) : null; } }