package org.radargun.service; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import org.infinispan.affinity.KeyAffinityService; import org.infinispan.affinity.KeyAffinityServiceFactory; import org.radargun.config.Init; import org.radargun.config.Property; import org.radargun.logging.Log; import org.radargun.logging.LogFactory; import org.radargun.stages.cache.generators.KeyGenerator; /** * A key generator using a key affinity service. All keys produced by this key generator * are local to the node that requested them. * The generator does not honour the keyIndex passed as argument and always returns a new unique key. * * Using shared keys with this generator is possible, but the set of generated keys is different on each node * (this is very likely even if the key format was identical, we ensure that by adding the local node address). * Initially only the local entries will be loaded into cache. Then, as the node executes PUT requests, the cache * will be filled with entries that are considered non-local, but have different keys. This will result in cache * with numEntries * numNodes. * Previous GET operation will return null values, naturally. * * Therefore, using shared keys with this generator is not advisable. * * Note for RadarGun integration: as key generators can be loaded only from core libraries, you have to use * <plugin-specific class="org.radargun.service.KeyAffinityStringKeyGenerator" * params="keyBufferSize:1000;cache=testCache" /> * to use this generator in test. * */ public class KeyAffinityStringKeyGenerator implements KeyGenerator { protected final Log log = LogFactory.getLog(KeyAffinityStringKeyGenerator.class); @Property(doc = "Number of generated keys per node.", optional = false) private int keyBufferSize; @Property(doc = "Name of the cache where the keys will be stored.", optional = false) private String cache; private KeyAffinityService affinityService; private ExecutorService executor; private AddressAwareStringKeyGenerator generator; private Infinispan51EmbeddedService wrapper; @Init public void init() { if (keyBufferSize <= 0 || cache == null) { throw new IllegalArgumentException("Invalid parameters provided, 'keyBufferSize' and 'cache' need to be specified."); } wrapper = Infinispan51EmbeddedService.getInstance(); } @Override public Object generateKey(long keyIndex) { synchronized (this) { if (affinityService == null) { newKeyAffinityService(); } } return affinityService.getKeyForAddress(wrapper.cacheManager.getAddress()); } private void newKeyAffinityService() { generator = new AddressAwareStringKeyGenerator(wrapper.cacheManager.getAddress().toString()); executor = Executors.newSingleThreadExecutor(); affinityService = KeyAffinityServiceFactory.newLocalKeyAffinityService(wrapper.cacheManager.getCache(cache), generator, executor, keyBufferSize); log.info("Created key affinity service with keyBufferSize: " + keyBufferSize); Runtime.getRuntime().addShutdownHook(new Thread() { public void run() { executor.shutdown(); } }); } protected class AddressAwareStringKeyGenerator implements org.infinispan.affinity.KeyGenerator { private String address; private long previousKey; /** * Address-aware constructor - key generator will generate different keys on each node. */ public AddressAwareStringKeyGenerator(String address) { this.address = address; } @Override public Object getKey() { return "key_" + address + "_" + previousKey++; } } }