/* * JBoss, Home of Professional Open Source * Copyright 2011 Red Hat Inc. and/or its affiliates and other * contributors as indicated by the @author tags. All rights reserved. * See the copyright.txt in the distribution for a full listing of * individual contributors. * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this software; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA, or see the FSF site: http://www.fsf.org. */ package org.infinispan.test; import org.infinispan.AdvancedCache; import org.infinispan.Cache; import org.infinispan.CacheImpl; import org.infinispan.cacheviews.CacheViewsManager; import org.infinispan.commands.CommandsFactory; import org.infinispan.commands.VisitableCommand; import org.infinispan.container.DataContainer; import org.infinispan.container.entries.CacheEntry; import org.infinispan.container.gmu.L1GMUContainer; import org.infinispan.context.InvocationContext; import org.infinispan.context.InvocationContextContainer; import org.infinispan.factories.ComponentRegistry; import org.infinispan.factories.GlobalComponentRegistry; import org.infinispan.factories.KnownComponentNames; import org.infinispan.interceptors.InterceptorChain; import org.infinispan.interceptors.base.CommandInterceptor; import org.infinispan.lifecycle.ComponentStatus; import org.infinispan.loaders.CacheLoader; import org.infinispan.loaders.CacheLoaderManager; import org.infinispan.manager.CacheContainer; import org.infinispan.manager.EmbeddedCacheManager; import org.infinispan.marshall.AbstractDelegatingMarshaller; import org.infinispan.marshall.StreamingMarshaller; import org.infinispan.marshall.jboss.ExternalizerTable; import org.infinispan.remoting.ReplicationQueue; import org.infinispan.remoting.rpc.RpcManager; import org.infinispan.remoting.transport.Address; import org.infinispan.remoting.transport.Transport; import org.infinispan.remoting.transport.jgroups.JGroupsTransport; import org.infinispan.statetransfer.StateTransferManager; import org.infinispan.transaction.TransactionTable; import org.infinispan.util.concurrent.locks.LockManager; import org.infinispan.util.logging.Log; import org.infinispan.util.logging.LogFactory; import org.jgroups.Channel; import org.jgroups.protocols.DELAY; import org.jgroups.protocols.DISCARD; import org.jgroups.protocols.TP; import org.jgroups.stack.ProtocolStack; import javax.management.ObjectName; import javax.transaction.Status; import javax.transaction.TransactionManager; import java.io.File; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Random; import java.util.Set; import java.util.concurrent.Callable; import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.LockSupport; import static java.io.File.separator; public class TestingUtil { private static final Log log = LogFactory.getLog(TestingUtil.class); private static final Random random = new Random(); public static final String TEST_PATH = "target" + separator + "tempFiles"; public static final String INFINISPAN_START_TAG = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<infinispan\n" + " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n" + " xsi:schemaLocation=\"urn:infinispan:config:5.2 http://www.infinispan.org/schemas/infinispan-config-5.2.xsd\"\n" + " xmlns=\"urn:infinispan:config:5.2\">"; public static final String INFINISPAN_START_TAG_40 = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<infinispan\n" + " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n" + " xsi:schemaLocation=\"urn:infinispan:config:4.0 http://www.infinispan.org/schemas/infinispan-config-4.0.xsd\"\n" + " xmlns=\"urn:infinispan:config:4.0\">"; public static final String INFINISPAN_END_TAG = "</infinispan>"; public static final String INFINISPAN_START_TAG_NO_SCHEMA = "<infinispan>"; /** * Extracts the value of a field in a given target instance using reflection, able to extract private fields as * well. * * @param target object to extract field from * @param fieldName name of field to extract * * @return field value */ public static Object extractField(Object target, String fieldName) { return extractField(target.getClass(), target, fieldName); } public static void replaceField(Object newValue, String fieldName, Object owner, Class baseType) { Field field; try { field = baseType.getDeclaredField(fieldName); field.setAccessible(true); field.set(owner, newValue); } catch (Exception e) { throw new RuntimeException(e);//just to simplify exception handling } } public static Object extractField(Class type, Object target, String fieldName) { while (true) { Field field; try { field = type.getDeclaredField(fieldName); field.setAccessible(true); return field.get(target); } catch (Exception e) { if (type.equals(Object.class)) { e.printStackTrace(); return null; } else { // try with superclass!! type = type.getSuperclass(); } } } } public static <T extends CommandInterceptor> T findInterceptor(Cache<?, ?> cache, Class<T> interceptorToFind) { for (CommandInterceptor i : cache.getAdvancedCache().getInterceptorChain()) { if (interceptorToFind.isInstance(i)) return interceptorToFind.cast(i); } return null; } public static void waitForRehashToComplete(Cache... caches) { // give it 1 second to start rehashing // TODO Should look at the last committed view instead and check if it contains all the caches LockSupport.parkNanos(TimeUnit.SECONDS.toNanos(1)); int gracetime = 30000; // 30 seconds? long giveup = System.currentTimeMillis() + gracetime; for (Cache c : caches) { CacheViewsManager cacheViewsManager = TestingUtil.extractGlobalComponent(c.getCacheManager(), CacheViewsManager.class); RpcManager rpcManager = TestingUtil.extractComponent(c, RpcManager.class); while (cacheViewsManager.getCommittedView(c.getName()).getMembers().size() != caches.length) { if (System.currentTimeMillis() > giveup) { String message = String.format("Timed out waiting for rehash to complete on node %s, expected member list is %s, current member list is %s!", rpcManager.getAddress(), Arrays.toString(caches), cacheViewsManager.getCommittedView(c.getName())); log.error(message); throw new RuntimeException(message); } LockSupport.parkNanos(TimeUnit.MILLISECONDS.toNanos(100)); } log.trace("Node " + rpcManager.getAddress() + " finished rehash task."); } } public static void waitForRehashToComplete(Cache cache, int groupSize) { LockSupport.parkNanos(TimeUnit.SECONDS.toNanos(1)); int gracetime = 30000; // 30 seconds? long giveup = System.currentTimeMillis() + gracetime; CacheViewsManager cacheViewsManager = TestingUtil.extractGlobalComponent(cache.getCacheManager(), CacheViewsManager.class); RpcManager rpcManager = TestingUtil.extractComponent(cache, RpcManager.class); while (cacheViewsManager.getCommittedView(cache.getName()).getMembers().size() != groupSize) { if (System.currentTimeMillis() > giveup) { String message = String.format("Timed out waiting for rehash to complete on node %s, expected member count %s, current member count is %s!", rpcManager.getAddress(), groupSize, cacheViewsManager.getCommittedView(cache.getName())); log.error(message); throw new RuntimeException(message); } LockSupport.parkNanos(TimeUnit.MILLISECONDS.toNanos(100)); } log.trace("Node " + rpcManager.getAddress() + " finished rehash task."); } public static void waitForRehashToComplete(Collection<? extends Cache> caches) { waitForRehashToComplete(caches.toArray(new Cache[caches.size()])); } /** * @deprecated Should use {@link #waitForRehashToComplete(org.infinispan.Cache[])} instead, this is not reliable with merges */ public static void waitForInitRehashToComplete(Cache... caches) { int gracetime = 30000; // 30 seconds? long giveup = System.currentTimeMillis() + gracetime; for (Cache c : caches) { StateTransferManager stateTransferManager = TestingUtil.extractComponent(c, StateTransferManager.class); RpcManager rpcManager = TestingUtil.extractComponent(c, RpcManager.class); while (!stateTransferManager.isJoinComplete()) { if (System.currentTimeMillis() > giveup) { String message = "Timed out waiting for join to complete on node " + rpcManager.getAddress() + " !"; log.error(message); throw new RuntimeException(message); } LockSupport.parkNanos(TimeUnit.MILLISECONDS.toNanos(100)); } log.trace("Node " + rpcManager.getAddress() + " finished join task."); } } /** * @deprecated Should use {@link #waitForRehashToComplete(org.infinispan.Cache[])} instead, this is not reliable with merges */ public static void waitForInitRehashToComplete(Collection<? extends Cache> caches) { Set<Cache> cachesSet = new HashSet<Cache>(); cachesSet.addAll(caches); waitForInitRehashToComplete(cachesSet.toArray(new Cache[cachesSet.size()])); } /** * Loops, continually calling {@link #areCacheViewsComplete(Cache[])} until it either returns true or * <code>timeout</code> ms have elapsed. * * @param caches caches which must all have consistent views * @param timeout max number of ms to loop * * @throws RuntimeException if <code>timeout</code> ms have elapse without all caches having the same number of * members. */ public static void blockUntilViewsReceived(Cache[] caches, long timeout) { long failTime = System.currentTimeMillis() + timeout; while (System.currentTimeMillis() < failTime) { sleepThread(100); if (areCacheViewsComplete(caches)) { return; } } viewsTimedOut(caches); } private static void viewsTimedOut(Cache[] caches) { CacheContainer[] cacheContainers = new CacheContainer[caches.length]; for (int i = 0; i < caches.length; i++) { cacheContainers[i] = caches[i].getCacheManager(); } viewsTimedOut(cacheContainers); } private static void viewsTimedOut(CacheContainer[] cacheContainers) { int length = cacheContainers.length; List<List<Address>> allViews = new ArrayList<List<Address>>(length); for (int i = 0; i < length; i++) { EmbeddedCacheManager cm = (EmbeddedCacheManager) cacheContainers[i]; allViews.add(cm.getMembers()); } throw new RuntimeException(String.format( "Timed out before caches had complete views. Expected %d members in each view. Views are as follows: %s", cacheContainers.length, allViews)); } public static void blockUntilViewsReceivedInt(Cache[] caches, long timeout) throws InterruptedException { long failTime = System.currentTimeMillis() + timeout; while (System.currentTimeMillis() < failTime) { sleepThreadInt(100, null); if (areCacheViewsComplete(caches)) { return; } } viewsTimedOut(caches); } /** * Version of blockUntilViewsReceived that uses varargs */ public static void blockUntilViewsReceived(long timeout, Cache... caches) { blockUntilViewsReceived(caches, timeout); } /** * Version of blockUntilViewsReceived that throws back any interruption */ public static void blockUntilViewsReceivedInt(long timeout, Cache... caches) throws InterruptedException { blockUntilViewsReceivedInt(caches, timeout); } /** * Version of blockUntilViewsReceived that uses varargsa and cache managers */ public static void blockUntilViewsReceived(long timeout, CacheContainer... cacheContainers) { blockUntilViewsReceived(timeout, true, cacheContainers); } /** * Waits for the given memebrs to be removed from the cluster. The difference between this and {@link * #blockUntilViewsReceived(long, org.infinispan.manager.CacheContainer...)} methods(s) is that it does not barf if * more than expected memebers is in the cluster - this is because we expect to start with a grater number fo * memebers than we eventually expect. It will barf though, if the number of members is not the one expected but only * after the timeout expieres. */ public static void blockForMemberToFail(long timeout, CacheContainer... cacheContainers) { blockUntilViewsReceived(timeout, false, cacheContainers); areCacheViewsComplete(true, cacheContainers); } public static void blockUntilViewsReceived(long timeout, boolean barfIfTooManyMembers, CacheContainer... cacheContainers) { long failTime = System.currentTimeMillis() + timeout; while (System.currentTimeMillis() < failTime) { sleepThread(100); if (areCacheViewsComplete(barfIfTooManyMembers, cacheContainers)) { return; } } viewsTimedOut(cacheContainers); } /** * Loops, continually calling {@link #areCacheViewsComplete(CacheSPI[])} until it either returns true or * <code>timeout</code> ms have elapsed. * * @param caches caches which must all have consistent views * @param timeout max number of ms to loop * @throws RuntimeException if <code>timeout</code> ms have elapse without all caches having the same number of * members. */ // public static void blockUntilViewsReceived(Cache[] caches, long timeout) { // long failTime = System.currentTimeMillis() + timeout; // // while (System.currentTimeMillis() < failTime) { // sleepThread(100); // if (areCacheViewsComplete(caches)) { // return; // } // } // // throw new RuntimeException("timed out before caches had complete views"); // } /** * An overloaded version of {@link #blockUntilViewsReceived(long,Cache[])} that allows for 'shrinking' clusters. * I.e., the usual method barfs if there are more members than expected. This one takes a param * (barfIfTooManyMembers) which, if false, will NOT barf but will wait until the cluster 'shrinks' to the desired * size. Useful if in tests, you kill a member and want to wait until this fact is known across the cluster. * * @param timeout * @param barfIfTooManyMembers * @param caches */ public static void blockUntilViewsReceived(long timeout, boolean barfIfTooManyMembers, Cache... caches) { long failTime = System.currentTimeMillis() + timeout; while (System.currentTimeMillis() < failTime) { sleepThread(100); if (areCacheViewsComplete(caches, barfIfTooManyMembers)) { return; } } viewsTimedOut(caches); } /** * Loops, continually calling {@link #areCacheViewsComplete(Cache[])} until it either returns true or * <code>timeout</code> ms have elapsed. * * @param groupSize number of caches expected in the group * @param timeout max number of ms to loop * * @throws RuntimeException if <code>timeout</code> ms have elapse without all caches having the same number of * members. */ public static void blockUntilViewReceived(Cache cache, int groupSize, long timeout) { blockUntilViewReceived(cache, groupSize, timeout, true); } public static void blockUntilViewReceived(Cache cache, int groupSize, long timeout, boolean barfIfTooManyMembersInView) { long failTime = System.currentTimeMillis() + timeout; while (System.currentTimeMillis() < failTime) { sleepThread(100); EmbeddedCacheManager cacheManager = cache.getCacheManager(); if (isCacheViewComplete(cacheManager.getMembers(), cacheManager.getAddress(), groupSize, barfIfTooManyMembersInView)) { return; } } throw new RuntimeException(String.format( "Timed out before cache had %d members. View is %s", groupSize, cache.getCacheManager().getMembers())); } /** * Checks each cache to see if the number of elements in the array returned by {@link * EmbeddedCacheManager#getMembers()} matches the size of the <code>caches</code> parameter. * * @param caches caches that should form a View * * @return <code>true</code> if all caches have <code>caches.length</code> members; false otherwise * * @throws IllegalStateException if any of the caches have MORE view members than caches.length */ public static boolean areCacheViewsComplete(Cache[] caches) { return areCacheViewsComplete(caches, true); } public static boolean areCacheViewsComplete(Cache[] caches, boolean barfIfTooManyMembers) { int memberCount = caches.length; for (int i = 0; i < memberCount; i++) { EmbeddedCacheManager cacheManager = caches[i].getCacheManager(); if (!isCacheViewComplete(cacheManager.getMembers(), cacheManager.getAddress(), memberCount, barfIfTooManyMembers)) { return false; } } return true; } public static boolean areCacheViewsComplete(boolean barfIfTooManyMembers, CacheContainer... cacheContainers) { if (cacheContainers == null) throw new NullPointerException("Cache Manager array is null"); int memberCount = cacheContainers.length; for (int i = 0; i < memberCount; i++) { EmbeddedCacheManager cacheManager = (EmbeddedCacheManager) cacheContainers[i]; if (!isCacheViewComplete(cacheManager.getMembers(), cacheManager.getAddress(), memberCount, barfIfTooManyMembers)) { return false; } } return true; } // /** // * @param cache // * @param memberCount // */ // public static boolean isCacheViewComplete(Cache cache, int memberCount) { // List members = cache.getCacheManager().getMembers(); // if (members == null || memberCount > members.size()) { // return false; // } else if (memberCount < members.size()) { // // This is an exceptional condition // StringBuilder sb = new StringBuilder("Cache at address "); // sb.append(cache.getCacheManager().getAddress()); // sb.append(" had "); // sb.append(members.size()); // sb.append(" members; expecting "); // sb.append(memberCount); // sb.append(". Members were ("); // for (int j = 0; j < members.size(); j++) { // if (j > 0) { // sb.append(", "); // } // sb.append(members.get(j)); // } // sb.append(')'); // // throw new IllegalStateException(sb.toString()); // } // // return true; // } /** * @param c * @param memberCount */ public static boolean isCacheViewComplete(Cache c, int memberCount) { EmbeddedCacheManager cacheManager = c.getCacheManager(); return isCacheViewComplete(cacheManager.getMembers(), cacheManager.getAddress(), memberCount, true); } public static boolean isCacheViewComplete(List members, Address address, int memberCount, boolean barfIfTooManyMembers) { if (members == null || memberCount > members.size()) { return false; } else if (memberCount < members.size()) { if (barfIfTooManyMembers) { // This is an exceptional condition StringBuilder sb = new StringBuilder("Cache at address "); sb.append(address); sb.append(" had "); sb.append(members.size()); sb.append(" members; expecting "); sb.append(memberCount); sb.append(". Members were ("); for (int j = 0; j < members.size(); j++) { if (j > 0) { sb.append(", "); } sb.append(members.get(j)); } sb.append(')'); throw new IllegalStateException(sb.toString()); } else return false; } return true; } /** * This method blocks until the given caches have a view of whose size * matches the desired value. This method is particularly useful for * discovering that members have been split, or that they have joined back * again. * * @param timeout max number of milliseconds to block for * @param finalViewSize desired final view size * @param caches caches representing current, or expected members in the cluster. */ public static void blockUntilViewsChanged(long timeout, int finalViewSize, Cache... caches) { blockUntilViewsChanged(caches, timeout, finalViewSize); } private static void blockUntilViewsChanged(Cache[] caches, long timeout, int finalViewSize) { long failTime = System.currentTimeMillis() + timeout; while (System.currentTimeMillis() < failTime) { sleepThread(100); if (areCacheViewsChanged(caches, finalViewSize)) { return; } } List<List<Address>> allViews = new ArrayList<List<Address>>(caches.length); for (int i = 0; i < caches.length; i++) { allViews.add(caches[i].getCacheManager().getMembers()); } throw new RuntimeException(String.format( "Timed out before caches had changed views (%s) to contain %d members", allViews, finalViewSize)); } private static boolean areCacheViewsChanged(Cache[] caches, int finalViewSize) { int memberCount = caches.length; for (int i = 0; i < memberCount; i++) { EmbeddedCacheManager cacheManager = caches[i].getCacheManager(); if (!isCacheViewChanged(cacheManager.getMembers(), finalViewSize)) { return false; } } return true; } private static boolean isCacheViewChanged(List members, int finalViewSize) { if (members == null || finalViewSize != members.size()) return false; else return true; } /** * Puts the current thread to sleep for the desired number of ms, suppressing any exceptions. * * @param sleeptime number of ms to sleep */ public static void sleepThread(long sleeptime) { sleepThread(sleeptime, null); } public static void sleepThread(long sleeptime, String messageOnInterrupt) { try { Thread.sleep(sleeptime); } catch (InterruptedException ie) { if (messageOnInterrupt != null) log.error(messageOnInterrupt); } } public static void sleepThreadInt(long sleeptime, String messageOnInterrupt) throws InterruptedException { try { Thread.sleep(sleeptime); } catch (InterruptedException ie) { if (messageOnInterrupt != null) log.error(messageOnInterrupt); throw ie; } } public static void sleepRandom(int maxTime) { sleepThread(random.nextInt(maxTime)); } public static void recursiveFileRemove(String directoryName) { File file = new File(directoryName); recursiveFileRemove(file); } public static void recursiveFileRemove(File file) { if (file.exists()) { System.out.println("Deleting file " + file); recursivedelete(file); } } private static void recursivedelete(File f) { if (f.isDirectory()) { File[] files = f.listFiles(); for (File file : files) { recursivedelete(file); } } //System.out.println("File " + f.toURI() + " deleted = " + f.delete()); f.delete(); } public static void killCacheManagers(CacheContainer... cacheContainers) { EmbeddedCacheManager[] cms = new EmbeddedCacheManager[cacheContainers.length]; for (int i = 0; i < cacheContainers.length; i++) cms[i] = (EmbeddedCacheManager) cacheContainers[i]; killCacheManagers(cms); } public static void killCacheManagers(List<? extends CacheContainer> cacheContainers) { EmbeddedCacheManager[] cms = new EmbeddedCacheManager[cacheContainers.size()]; for (int i = 0; i < cacheContainers.size(); i++) cms[i] = (EmbeddedCacheManager) cacheContainers.get(i); killCacheManagers(cms); } public static void killCacheManagers(EmbeddedCacheManager... cacheManagers) { // stop the caches first so that stopping the cache managers doesn't trigger a rehash for (EmbeddedCacheManager cm : cacheManagers) { try { killCaches(getRunningCaches(cm)); } catch (Throwable e) { log.warn("Problems stopping cache manager " + cm, e); } } for (EmbeddedCacheManager cm : cacheManagers) { try { if (cm != null) cm.stop(); } catch (Throwable e) { log.warn("Problems killing cache manager " + cm, e); } } } public static void clearContent(EmbeddedCacheManager... cacheManagers) { clearContent(Arrays.asList(cacheManagers)); } public static void clearContent(List<? extends EmbeddedCacheManager> cacheManagers) { for (EmbeddedCacheManager cm : cacheManagers) { try { clearContent(cm); } catch (Throwable e) { log.warn("Problems clearing cache manager " + cm, e); } } } public static void clearContent(EmbeddedCacheManager cacheContainer) { if (cacheContainer != null && cacheContainer.getStatus().allowInvocations()) { Set<Cache> runningCaches = getRunningCaches(cacheContainer); for (Cache cache : runningCaches) { clearRunningTx(cache); } if (!cacheContainer.getStatus().allowInvocations()) return; for (Cache cache : runningCaches) { clearReplicationQueues(cache); clearCacheLoader(cache); removeInMemoryData(cache); } } } protected static Set<Cache> getRunningCaches(EmbeddedCacheManager cacheContainer) { Set<Cache> running = new HashSet<Cache>(); if (cacheContainer == null || !cacheContainer.getStatus().allowInvocations()) return running; for (String cacheName : cacheContainer.getCacheNames()) { if (cacheContainer.isRunning(cacheName)) { Cache c = cacheContainer.getCache(cacheName); if (c.getStatus().allowInvocations()) running.add(c); } } if (cacheContainer.isDefaultRunning()) { Cache defaultCache = cacheContainer.getCache(); if (defaultCache.getStatus().allowInvocations()) running.add(defaultCache); } return running; } private static void clearRunningTx(Cache cache) { if (cache != null) { TransactionManager txm = TestingUtil.getTransactionManager(cache); if (txm == null) return; try { txm.rollback(); } catch (Exception e) { // don't care } } } private static void clearReplicationQueues(Cache cache) { ReplicationQueue queue = TestingUtil.extractComponent(cache, ReplicationQueue.class); if (queue != null) queue.reset(); } public static void clearCacheLoader(Cache cache) { CacheLoaderManager cacheLoaderManager = TestingUtil.extractComponent(cache, CacheLoaderManager.class); if (cacheLoaderManager != null && cacheLoaderManager.getCacheStore() != null) { try { cacheLoaderManager.getCacheStore().clear(); } catch (Exception e) { throw new RuntimeException(e); } } } private static void removeInMemoryData(Cache cache) { EmbeddedCacheManager mgr = cache.getCacheManager(); Address a = mgr.getAddress(); String str; if (a == null) str = "a non-clustered cache manager"; else str = "a cache manager at address " + a; log.debugf("Cleaning data for cache '%s' on %s", cache.getName(), str); DataContainer dataContainer = TestingUtil.extractComponent(cache, DataContainer.class); if (log.isDebugEnabled()) log.debugf("removeInMemoryData(): dataContainerBefore == %s", dataContainer.entrySet(null)); dataContainer.clear(); if (log.isDebugEnabled()) log.debugf("removeInMemoryData(): dataContainerAfter == %s", dataContainer.entrySet(null)); L1GMUContainer l1GMUContainer = TestingUtil.extractComponent(cache, L1GMUContainer.class); if (log.isDebugEnabled()) log.debugf("removeInMemoryData(): l1GMUContainerBefore == %s", l1GMUContainer.chainToString()); l1GMUContainer.clear(); if (log.isDebugEnabled()) log.debugf("removeInMemoryData(): l1GMUContainerAfter == %s", l1GMUContainer.chainToString()); } /** * Kills a cache - stops it, clears any data in any cache loaders, and rolls back any associated txs */ public static void killCaches(Cache... caches) { killCaches(Arrays.asList(caches)); } /** * Kills a cache - stops it and rolls back any associated txs */ public static void killCaches(Collection<Cache> caches) { for (Cache c : caches) { try { if (c != null && c.getStatus() == ComponentStatus.RUNNING) { TransactionManager tm = getTransactionManager(c); if (tm != null) { try { tm.rollback(); } catch (Exception e) { // don't care } } log.tracef("Cache contents before stopping: %s", c.entrySet()); c.stop(); } } catch (Throwable t) { } } } /** * Clears transaction with the current thread in the given transaction manager. * * @param txManager a TransactionManager to be cleared */ public static void killTransaction(TransactionManager txManager) { if (txManager != null) { try { txManager.rollback(); } catch (Exception e) { // don't care } } } /** * Clears any associated transactions with the current thread in the caches' transaction managers. */ public static void killTransactions(Cache... caches) { for (Cache c : caches) { if (c != null && c.getStatus() == ComponentStatus.RUNNING) { TransactionManager tm = getTransactionManager(c); if (tm != null) { try { tm.rollback(); } catch (Exception e) { // don't care } } } } } /** * For testing only - introspects a cache and extracts the ComponentRegistry * * @param cache cache to introspect * * @return component registry */ public static ComponentRegistry extractComponentRegistry(Cache cache) { ComponentRegistry cr = (ComponentRegistry) extractField(cache, "componentRegistry"); if (cr == null) cr = cache.getAdvancedCache().getComponentRegistry(); return cr; } public static GlobalComponentRegistry extractGlobalComponentRegistry(CacheContainer cacheContainer) { return (GlobalComponentRegistry) extractField(cacheContainer, "globalComponentRegistry"); } public static LockManager extractLockManager(Cache cache) { return extractComponentRegistry(cache).getComponent(LockManager.class); } /** * For testing only - introspects a cache and extracts the ComponentRegistry * * @param ci interceptor chain to introspect * * @return component registry */ public static ComponentRegistry extractComponentRegistry(InterceptorChain ci) { return (ComponentRegistry) extractField(ci, "componentRegistry"); } public static AbstractDelegatingMarshaller extractCacheMarshaller(Cache cache) { ComponentRegistry cr = (ComponentRegistry) extractField(cache, "componentRegistry"); StreamingMarshaller marshaller = cr.getComponent(StreamingMarshaller.class, KnownComponentNames.CACHE_MARSHALLER); return (AbstractDelegatingMarshaller) marshaller; } public static AbstractDelegatingMarshaller extractGlobalMarshaller(EmbeddedCacheManager cm) { GlobalComponentRegistry gcr = (GlobalComponentRegistry) extractField(cm, "globalComponentRegistry"); return (AbstractDelegatingMarshaller) gcr.getComponent(StreamingMarshaller.class, KnownComponentNames.GLOBAL_MARSHALLER); } public static ExternalizerTable extractExtTable(CacheContainer cacheContainer) { GlobalComponentRegistry gcr = (GlobalComponentRegistry) extractField(cacheContainer, "globalComponentRegistry"); return gcr.getComponent(ExternalizerTable.class); } /** * Replaces the existing interceptor chain in the cache wih one represented by the interceptor passed in. This * utility updates dependencies on all components that rely on the interceptor chain as well. * * @param cache cache that needs to be altered * @param interceptor the first interceptor in the new chain. */ public static void replaceInterceptorChain(Cache cache, CommandInterceptor interceptor) { ComponentRegistry cr = extractComponentRegistry(cache); // make sure all interceptors here are wired. CommandInterceptor i = interceptor; do { cr.wireDependencies(i); } while ((i = i.getNext()) != null); InterceptorChain inch = cr.getComponent(InterceptorChain.class); inch.setFirstInChain(interceptor); } /** * Replaces an existing interceptor of the given type in the interceptor chain with a new interceptor instance passed * as parameter. * * @param replacingInterceptor the interceptor to add to the interceptor chain * @param toBeReplacedInterceptorType the type of interceptor that should be swapped with the new one * * @return true if the interceptor was replaced */ public static boolean replaceInterceptor(Cache cache, CommandInterceptor replacingInterceptor, Class<? extends CommandInterceptor> toBeReplacedInterceptorType) { ComponentRegistry cr = extractComponentRegistry(cache); // make sure all interceptors here are wired. CommandInterceptor i = replacingInterceptor; do { cr.wireDependencies(i); } while ((i = i.getNext()) != null); InterceptorChain inch = cr.getComponent(InterceptorChain.class); return inch.replaceInterceptor(replacingInterceptor, toBeReplacedInterceptorType); } /** * Retrieves the remote delegate for a given cache. It is on this remote delegate that the JGroups RPCDispatcher * invokes remote methods. * * @param cache cache instance for which a remote delegate is to be retrieved * * @return remote delegate, or null if the cacge is not configured for replication. */ public static CacheImpl getInvocationDelegate(Cache cache) { return (CacheImpl) cache; } /** * Blocks until the cache has reached a specified state. * * @param cache cache to watch * @param cacheStatus status to wait for * @param timeout timeout to wait for */ public static void blockUntilCacheStatusAchieved(Cache cache, ComponentStatus cacheStatus, long timeout) { AdvancedCache spi = cache.getAdvancedCache(); long killTime = System.currentTimeMillis() + timeout; while (System.currentTimeMillis() < killTime) { if (spi.getStatus() == cacheStatus) return; sleepThread(50); } throw new RuntimeException("Timed out waiting for condition"); } public static void replicateCommand(Cache cache, VisitableCommand command) throws Throwable { ComponentRegistry cr = extractComponentRegistry(cache); InterceptorChain ic = cr.getComponent(InterceptorChain.class); InvocationContextContainer icc = cr.getComponent(InvocationContextContainer.class); InvocationContext ctxt = icc.createInvocationContext(true, -1); ic.invoke(ctxt, command); } public static void blockUntilViewsReceived(int timeout, Collection caches) { Object first = caches.iterator().next(); if (first instanceof Cache) { blockUntilViewsReceived(timeout, (Cache[]) caches.toArray(new Cache[]{})); } else { blockUntilViewsReceived(timeout, (CacheContainer[]) caches.toArray(new CacheContainer[]{})); } } public static void blockUntilViewsReceived(int timeout, boolean barfIfTooManyMembers, Collection caches) { Object first = caches.iterator().next(); if (first instanceof Cache) { blockUntilViewsReceived(timeout, barfIfTooManyMembers, (Cache[]) caches.toArray(new Cache[]{})); } else { blockUntilViewsReceived(timeout, barfIfTooManyMembers, (CacheContainer[]) caches.toArray(new CacheContainer[]{})); } } public static CommandsFactory extractCommandsFactory(Cache<Object, Object> cache) { return (CommandsFactory) extractField(cache, "commandsFactory"); } public static void dumpCacheContents(List caches) { System.out.println("**** START: Cache Contents ****"); int count = 1; for (Object o : caches) { Cache c = (Cache) o; if (c == null) { System.out.println(" ** Cache " + count + " is null!"); } else { EmbeddedCacheManager cacheManager = c.getCacheManager(); System.out.println(" ** Cache " + count + " is " + cacheManager.getAddress()); } count++; } System.out.println("**** END: Cache Contents ****"); } public static void dumpCacheContents(Cache... caches) { dumpCacheContents(Arrays.asList(caches)); } /** * Extracts a component of a given type from the cache's internal component registry */ public static <T> T extractComponent(Cache cache, Class<T> componentType) { ComponentRegistry cr = extractComponentRegistry(cache); return cr.getComponent(componentType); } /** * Extracts a component of a given type from the cache's internal component registry */ public static <T> T extractGlobalComponent(CacheContainer cacheContainer, Class<T> componentType) { GlobalComponentRegistry gcr = extractGlobalComponentRegistry(cacheContainer); return gcr.getComponent(componentType); } public static TransactionManager getTransactionManager(Cache cache) { return cache == null ? null : extractComponent(cache, TransactionManager.class); } /** * Replaces a component in a running cache * * @param cache cache in which to replace component * @param componentType component type of which to replace * @param replacementComponent new instance * @param rewire if true, ComponentRegistry.rewire() is called after replacing. * * @return the original component that was replaced */ public static <T> T replaceComponent(Cache<?, ?> cache, Class<T> componentType, T replacementComponent, boolean rewire) { ComponentRegistry cr = extractComponentRegistry(cache); T old = cr.getComponent(componentType); cr.registerComponent(replacementComponent, componentType); if (rewire) cr.rewire(); return old; } /** * Replaces a component in a running cache manager (global component registry) * * @param cacheContainer cache in which to replace component * @param componentType component type of which to replace * @param replacementComponent new instance * @param rewire if true, ComponentRegistry.rewire() is called after replacing. * * @return the original component that was replaced */ public static <T> T replaceComponent(CacheContainer cacheContainer, Class<T> componentType, T replacementComponent, boolean rewire) { GlobalComponentRegistry cr = extractGlobalComponentRegistry(cacheContainer); T old = cr.getComponent(componentType); cr.registerComponent(replacementComponent, componentType); if (rewire) { cr.rewire(); cr.rewireNamedRegistries(); } return old; } public static CacheLoader getCacheLoader(Cache cache) { CacheLoaderManager clm = extractComponent(cache, CacheLoaderManager.class); if (clm != null && clm.isEnabled()) { return clm.getCacheLoader(); } else { return null; } } public static String printCache(Cache cache) { DataContainer dataContainer = TestingUtil.extractComponent(cache, DataContainer.class); Iterator it = dataContainer.iterator(); StringBuilder builder = new StringBuilder(cache.getName() + "["); while (it.hasNext()) { CacheEntry ce = (CacheEntry) it.next(); builder.append(ce.getKey() + "=" + ce.getValue() + ",l=" + ce.getLifespan() + "; "); } builder.append("]"); return builder.toString(); } public static Set getInternalKeys(Cache cache) { DataContainer dataContainer = TestingUtil.extractComponent(cache, DataContainer.class); Set keys = new HashSet(); for (CacheEntry entry : dataContainer) { keys.add(entry.getKey()); } return keys; } public static Collection getInternalValues(Cache cache) { DataContainer dataContainer = TestingUtil.extractComponent(cache, DataContainer.class); Collection values = new ArrayList(); for (CacheEntry entry : dataContainer) { values.add(entry.getValue()); } return values; } public static DISCARD getDiscardForCache(Cache<?, ?> c) throws Exception { JGroupsTransport jgt = (JGroupsTransport) TestingUtil.extractComponent(c, Transport.class); Channel ch = jgt.getChannel(); ProtocolStack ps = ch.getProtocolStack(); DISCARD discard = new DISCARD(); ps.insertProtocol(discard, ProtocolStack.ABOVE, TP.class); return discard; } /** * Inserts a DELAY protocol in the JGroups stack used by the cache, and returns it. * The DELAY protocol can then be used to inject delays in milliseconds both at receiver * and sending side. * @param cache * @param in_delay_millis * @param out_delay_millis * @return a reference to the DELAY instance being used by the JGroups stack * @throws Exception */ public static DELAY setDelayForCache(Cache<?, ?> cache, int in_delay_millis, int out_delay_millis) throws Exception { JGroupsTransport jgt = (JGroupsTransport) TestingUtil.extractComponent(cache, Transport.class); Channel ch = jgt.getChannel(); ProtocolStack ps = ch.getProtocolStack(); DELAY delay = new DELAY(); delay.setInDelay(in_delay_millis); delay.setOutDelay(out_delay_millis); ps.insertProtocol(delay, ProtocolStack.ABOVE, TP.class); return delay; } /** * Creates a path to a temp directory based on a base directory and a test. * * @param basedir may be null, if relative directories are to be used. * @param test test that requires this directory. * * @return a path, relative or absolute. */ public static String tmpDirectory(String basedir, AbstractInfinispanTest test) { String prefix = ""; if (basedir != null) { prefix = basedir; if (!prefix.endsWith(separator)) prefix += separator; } return prefix + TEST_PATH + separator + test.getClass().getSimpleName(); } public static String k(Method method, int index) { return new StringBuilder().append("k").append(index).append('-') .append(method.getName()).toString(); } public static String v(Method method, int index) { return new StringBuilder().append("v").append(index).append('-') .append(method.getName()).toString(); } public static String k(Method method) { return k(method, 0); } public static String v(Method method) { return v(method, 0); } public static TransactionTable getTransactionTable(Cache<Object, Object> cache) { return cache.getAdvancedCache().getComponentRegistry().getComponent(TransactionTable.class); } public static String getMethodSpecificJmxDomain(Method m, String jmxDomain) { return jmxDomain + '.' + m.getName(); } public static ObjectName getCacheManagerObjectName(String jmxDomain) throws Exception { return getCacheManagerObjectName(jmxDomain, "DefaultCacheManager"); } public static ObjectName getCacheManagerObjectName(String jmxDomain, String cacheManagerName) throws Exception { return new ObjectName(jmxDomain + ":type=CacheManager,name=" + ObjectName.quote(cacheManagerName) + ",component=CacheManager"); } public static ObjectName getCacheObjectName(String jmxDomain) throws Exception { return getCacheObjectName(jmxDomain, CacheContainer.DEFAULT_CACHE_NAME + "(local)"); } public static ObjectName getCacheObjectName(String jmxDomain, String cacheName) throws Exception { return getCacheObjectName(jmxDomain, cacheName, "Cache"); } public static ObjectName getCacheObjectName(String jmxDomain, String cacheName, String component) throws Exception { return getCacheObjectName(jmxDomain, cacheName, component, "DefaultCacheManager"); } public static ObjectName getCacheObjectName(String jmxDomain, String cacheName, String component, String cacheManagerName) throws Exception { return new ObjectName(jmxDomain + ":type=Cache,manager=" + ObjectName.quote(cacheManagerName) + ",name=" + ObjectName.quote(cacheName) + ",component=" + component); } public static ObjectName getJGroupsChannelObjectName(String jmxDomain, String clusterName) throws Exception { return new ObjectName(String.format("%s:type=channel,cluster=%s", jmxDomain, ObjectName.quote(clusterName))); } public static String generateRandomString(int numberOfChars) { Random r = new Random(System.currentTimeMillis()); StringBuilder sb = new StringBuilder(); for (int i = 0; i < numberOfChars; i++) sb.append((char) (64 + r.nextInt(26))); return sb.toString(); } /** * Verifies the cache doesn't contain any lock * @param cache */ public static void assertNoLocks(Cache<?,?> cache) { LockManager lm = TestingUtil.extractLockManager(cache); for (Object key : cache.keySet()) assert !lm.isLocked(key); } /** * Call an operation within a transaction. This method guarantees that the * right pattern is used to make sure that the transaction is always either * committed or rollbacked. * * @param tm transaction manager * @param c callable instance to run within a transaction * @param <T> type of callable return * @return returns whatever the callable returns * @throws Exception */ public static <T> T withTx(TransactionManager tm, Callable<T> c) throws Exception { tm.begin(); try { return c.call(); } catch (Exception e) { tm.setRollbackOnly(); throw e; } finally { if (tm.getStatus() == Status.STATUS_ACTIVE) tm.commit(); else tm.rollback(); } } /** * Invoke a task using a cache manager. This method guarantees that the * cache manager used in the task will be cleaned up after the task has * completed, regardless of the task outcome. * * @param c task to execute * @throws Exception if the task fails somehow */ public static void withCacheManager(CacheManagerCallable c) throws Exception { try { c.call(); } finally { TestingUtil.killCacheManagers(c.cm); } } /** * Invoke a task using a several cache managers. This method guarantees * that the cache managers used in the task will be cleaned up after the * task has completed, regardless of the task outcome. * * @param c task to execute * @throws Exception if the task fails somehow */ public static void withCacheManagers(MultiCacheManagerCallable c) throws Exception { try { c.call(); } finally { TestingUtil.killCacheManagers(c.cms); } } }