/* * ProActive Parallel Suite(TM): * The Open Source library for parallel and distributed * Workflows & Scheduling, Orchestration, Cloud Automation * and Big Data Analysis on Enterprise Grids & Clouds. * * Copyright (c) 2007 - 2017 ActiveEon * Contact: contact@activeeon.com * * This library is free software: you can redistribute it and/or * modify it under the terms of the GNU Affero General Public License * as published by the Free Software Foundation: version 3 of * the License. * * This program 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 Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * * If needed, contact us to obtain a release under GPL Version 2 or 3 * or a different license than the AGPL. */ package org.ow2.proactive.resourcemanager.frontend.topology; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; import java.net.InetAddress; import java.rmi.dgc.VMID; import java.util.ArrayList; import java.util.List; import java.util.concurrent.Callable; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; import org.apache.log4j.BasicConfigurator; import org.apache.log4j.Level; import org.apache.log4j.Logger; import org.junit.Assert; import org.junit.Test; import org.objectweb.proactive.core.UniqueID; import org.objectweb.proactive.core.node.NodeImpl; import org.objectweb.proactive.core.runtime.ProActiveRuntimeImpl; import org.objectweb.proactive.core.runtime.VMInformation; import org.objectweb.proactive.core.util.ProActiveInet; import org.ow2.proactive.resourcemanager.core.properties.PAResourceManagerProperties; import org.ow2.proactive.resourcemanager.frontend.topology.pinging.HostsPinger; import org.ow2.proactive.resourcemanager.selection.topology.TopologyManager; /** * Test add and remove nodes from multiple threads * <p/> * At the end, remove all previously added nodes and verify that * the topology manager structure is empty */ public class topologyConcurrencyTest { // number of thread used in this test final int nbThreads = 20; // multiplier for the number of nodes to create final int nodeFactor = 4; // size of collisions, as many operations will be done on the same node // more removal than add final int collisionSize = 10; // total number of tasks final int total = nbThreads * nodeFactor * collisionSize; String baseUrl = "pnp://localhost:1234/LocalNode-"; ExecutorService s = Executors.newFixedThreadPool(nbThreads); @Test public void action() throws Exception { BasicConfigurator.resetConfiguration(); BasicConfigurator.configure(); Logger.getLogger(TopologyManager.class).setLevel(Level.DEBUG); PAResourceManagerProperties.RM_TOPOLOGY_PINGER.updateProperty(HostsPinger.class.getName()); PAResourceManagerProperties.RM_TOPOLOGY_ENABLED.updateProperty("true"); PAResourceManagerProperties.RM_TOPOLOGY_DISTANCE_ENABLED.updateProperty("false"); final ProActiveRuntimeImpl runtime = mock(ProActiveRuntimeImpl.class); when(runtime.getVMInformation()).thenReturn(new DummyVMInfo()); final TopologyManager manager = new TopologyManager(); List<Callable<Boolean>> calls = new ArrayList<>(total); // first set of tasks, add nodes and remove them for (int i = 0; i < total; i++) { final int j = i; calls.add(new Callable<Boolean>() { @Override public Boolean call() throws Exception { int index = j - (j % collisionSize); NodeImpl node = new NodeImpl(runtime, baseUrl + index); if ((j % (collisionSize / 2)) == 0) { manager.addNode(node); } else { // more remove than add, to try to reproduce empty list problems manager.removeNode(node); } return true; } }); } List<Future<Boolean>> futures = s.invokeAll(calls); for (Future<Boolean> fut : futures) { Assert.assertTrue(fut.get()); } calls = new ArrayList<>(nbThreads * nodeFactor); // second set of task remove all nodes created for (int i = 0; i < total; i += collisionSize) { final int j = i; calls.add(new Callable<Boolean>() { @Override public Boolean call() throws Exception { int index = j; manager.removeNode(new NodeImpl(runtime, baseUrl + index)); return true; } }); } futures = s.invokeAll(calls); for (Future<Boolean> fut : futures) { Assert.assertTrue(fut.get()); } System.out.println(manager.getTopology().getHosts()); // finally verify that the nodes on host structure is empty (null) Assert.assertNull(manager.getNodesOnHost(DummyVMInfo.address)); } public static class DummyVMInfo implements VMInformation { static VMID vmId = UniqueID.getCurrentVMID(); static java.net.InetAddress address = ProActiveInet.getInstance().getInetAddress(); static String hostname = ProActiveInet.getInstance().getHostname(); @Override public VMID getVMID() { return vmId; } @Override public InetAddress getInetAddress() { return address; } @Override public String getName() { return null; } @Override public String getHostName() { return hostname; } @Override public String getDescriptorVMName() { return null; } @Override public long getCapacity() { return 0; } @Override public long getDeploymentId() { return 0; } @Override public long getTopologyId() { return 0; } } }