Oracle Coherence data grid. Challenge: To test a cluster you need a cluster. Solution: Simulate a cluster, manage “virtualized” java process with smooth API. Plus, a lot of neat stuff to manage Coherence nodes.
public void simple_cluster() { // Present for typical single node cluster cloud.all().presetFastLocalCluster(); cloud.node("storage.**").localStorage(true); cloud.node("client.**").localStorage(false); // Simulates DefaultCacheServer based process cloud.node("storage.**").autoStartServices(); // declaring specific nodes to be created CohNode storage = cloud.node("storage.1"); CohNode client1 = cloud.node("client.1"); CohNode client2 = cloud.node("client.2"); // now we have 3 specific nodes in cloud // all of then will be initialized in parallel cloud.all().ensureCluster(); final String cacheName = "distr-a"; client1.exec(new Runnable() { @Override public void run() { NamedCache cache = CacheFactory.getCache(cacheName); Assert.assertNull(cache.get("A")); cache.put("A", "aaa"); } }); client2.exec(new Runnable() { @Override public void run() { NamedCache cache = CacheFactory.getCache(cacheName); Assert.assertEquals("aaa", cache.get("A")); } }); }
public void simple_cluster() { // Present for typical single node cluster cloud.all().presetFastLocalCluster(); cloud object is managing all your virtual nodes @Rule will ensure that all nodes created in test would be terminated Common settings for “virtual” cluster: WKA, timeouts, etc Will apply to all nodes in this cluster
cloud.node("client.**").localStorage(false); // Simulates DefaultCacheServer based process cloud.node("storage.**").autoStartServices(); Simulate DefaultCacheServer behavior for stoarge nodes Using wild card in node name, creates a rule which will apply all matching nodes
storage = cloud.node("storage.1"); CohNode client1 = cloud.node("client.1"); CohNode client2 = cloud.node("client.2"); Our cluster will have one storage enabled and 2 storage disable nodes Mentioning a node name without a wild card is a declaration of specific node Nothing is created at this point, initialization is lazy
cloud // all of then will be initialized in parallel cloud.all().ensureCluster(); All nodes which have been declare will be initialized in parallel. Coherence loads about 5000 classes, utilizing more CPU cores provides noticeable speed up “Virtual” nodes are initialized once on first attemp to execute something inside of node Convenient method to call CacheFactory.ensureCluster() for “virtual” node
NamedCache cache = CacheFactory.getCache(cacheName); Assert.assertNull(cache.get("A")); cache.put("A", "aaa"); } }); exec will execute Runnable or Callable synchronously in context of your virtual nodes This object will be “recreated” in different classloader and executed in different thread You can use JUnit’s Assert here. Exception will be forwarded to caller. You can use Coherence API in the usual way
created in JUnit test Nodes have independent configuration Nodes have independent system properties You can execute arbitrary code in scope of any node Parallel initialization Can be run under debugger
put(Object key, Object value); } RemotePut remoteService = client1.exec(new Callable<RemotePut>() { @Override public RemotePut call() { final NamedCache cache = CacheFactory.getCache(cacheName); return new RemotePut() { @Override public void put(Object key, Object value) { cache.put(key, value); } }; } }); remoteService.put("A", "aaa"); Extending java.rmi.Remotexec will mark interface for auto export Unlike Java RMI, there is no need to declare RemoteException for every method Result of callable will be serialized and transferred to caller Objects implementing remote interfaces are automatically replaced with remote stub during serialization Here we got a remote stub, not a real implementation of interface Call to a stub, will be converted to “remote” call to instance we have created in “virtualized” node few lines above
enough … • node.outOfProcess(true) • separate slave JVM process will be spawned • same API will work for out-of-process nodes • JVM options (e.g. -Xmx) could be passed • slave’s console will be prefixed and show on master • if master process dies, slave will die too • even if master has been killed by debugger or kill -9
include or exclude jars from classpath • works for both classloader isolation and out-of-process slaves • you can start cluster with different versions of coherence.jar • for your convenience node.useCoherenceVersion("3.7.1.8") current version of cohernce.jar would be excluded required version would be included from … … eigther local maven cache … … or from resources (should packaged in special way)
long for a test! For in-process node, shutdown will kill all threads thread in its scope TCP ring detects process liveliness, it will prevent death detection of “virtualized”node cloud.all().setTCMPTimeout(15000); cloud.all().enableTcpRing(false); cloud.node("server.0").shutdown(); System.out.println("It takes some time for Coherence" + " to detect node failure is \"virtualized\" node"); For out-of-process node, its process would be destroyed.