/* * 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 functionaltests.monitor; import java.util.ArrayList; import java.util.List; import org.objectweb.proactive.core.ProActiveTimeoutException; import org.objectweb.proactive.utils.TimeoutAccounter; import org.ow2.proactive.resourcemanager.common.event.RMEventType; import org.ow2.proactive.resourcemanager.common.event.RMNodeEvent; import org.ow2.proactive.resourcemanager.common.event.RMNodeSourceEvent; import functionaltests.utils.RMTHelper; public class RMMonitorsHandler { /** * Event concerning RM State (started, killed, etc) * and not yet checked by a waiter. */ private List<RMEventType> stateEvents; /** * Event concerning nodes sources. * and not yet checked by a waiter. */ private List<NodeSourceEventMonitor> nodeSourcesEvent; /** * Event concerning nodes,(added, busy, down...) * and not yet checked by a waiter. */ private List<NodeEventMonitor> nodesEvent; /** * Awaited event from Scheduler ; * a list of monitors, used for synchronization with threads that have called waitForEvent**() * methods. These monitors are notified only if corresponding event is thrown by Scheduler */ private List<RMEventMonitor> eventsMonitors; public RMMonitorsHandler() { stateEvents = new ArrayList<>(); nodeSourcesEvent = new ArrayList<>(); nodesEvent = new ArrayList<>(); eventsMonitors = new ArrayList<>(); } /** * Clears this monitor state in case of reconnection */ public void clear() { stateEvents.clear(); nodesEvent.clear(); nodesEvent.clear(); eventsMonitors.clear(); } public void waitForRMStateEvent(RMEventType eventType, long timeout) throws ProActiveTimeoutException { RMEventMonitor monitor = null; synchronized (this) { if (stateEvents.contains(eventType)) { stateEvents.remove(eventType); return; } monitor = getMonitor(new RMEventMonitor(eventType)); } waitWithMonitor(monitor, timeout); } public void waitForNodesourceEvent(RMEventType eventType, String nodeSourceName, long timeout) throws ProActiveTimeoutException { NodeSourceEventMonitor monitor = new NodeSourceEventMonitor(eventType, nodeSourceName); synchronized (this) { if (this.nodeSourcesEvent.contains(monitor)) { nodeSourcesEvent.remove(monitor); return; } monitor = (NodeSourceEventMonitor) getMonitor(new NodeSourceEventMonitor(eventType, nodeSourceName)); } waitWithMonitor(monitor, timeout); } public RMNodeEvent waitForNodeEvent(RMEventType eventType, String nodeUrl, long timeout) throws ProActiveTimeoutException { NodeEventMonitor monitor = new NodeEventMonitor(eventType, nodeUrl); synchronized (this) { if (this.nodesEvent.contains(monitor)) { RMNodeEvent event = nodesEvent.get(nodesEvent.indexOf(monitor)).getNodeEvent(); nodesEvent.remove(monitor); return event; } monitor = (NodeEventMonitor) getMonitor(monitor); } waitWithMonitor(monitor, timeout); return monitor.getNodeEvent(); } public RMNodeEvent waitForAnyNodeEvent(RMEventType eventType, long timeout) throws ProActiveTimeoutException { NodeEventMonitor monitor = new NodeEventMonitor(eventType, ""); synchronized (this) { for (NodeEventMonitor e : nodesEvent) { if (e.getWaitedEvent().equals(eventType)) { nodesEvent.remove(e); return e.getNodeEvent(); } } monitor = (NodeEventMonitor) getMonitor(monitor); } waitWithMonitor(monitor, timeout); return monitor.getNodeEvent(); } /** * * @param eventType */ public void handleSchedulerStateEvent(RMEventType eventType) { synchronized (this) { if (!lookAndNotifyMonitor(new RMEventMonitor(eventType))) { this.stateEvents.add(eventType); } } } /** * * @param event */ public void handleNodesourceEvent(RMNodeSourceEvent event) { synchronized (this) { NodeSourceEventMonitor nsem = new NodeSourceEventMonitor(event.getEventType(), event.getSourceName()); if (!lookAndNotifyMonitor(nsem)) { this.nodeSourcesEvent.add(nsem); } } } /** * * @param event */ public void handleNodeEvent(RMNodeEvent event) { synchronized (this) { boolean anyNodeMonitorFound = false; boolean specificNodeMonitorFound = false; //notify eventual monitors that wait for an 'any node event', //i.e a specific node Event, but not occurred on a specific node NodeEventMonitor nem = new NodeEventMonitor(event.getEventType(), "", event); if (lookAndNotifyMonitor(nem)) { anyNodeMonitorFound = true; } //notify eventual monitors that wait for any 'a specific any node event', //i.e a specific node Event, on a specific node, specified by Url nem = new NodeEventMonitor(event.getEventType(), event.getNodeUrl(), event); if (lookAndNotifyMonitor(nem)) { specificNodeMonitorFound = true; } //no monitor has consumed this event, store it if (!(anyNodeMonitorFound || specificNodeMonitorFound)) { this.nodesEvent.add(nem); } } } //---------------------------------------------------------------// //private methods // these methods MUST be called from a synchronized(this) block //---------------------------------------------------------------// /** * Notify threads, if any that wait for a specific event * * @param monitor TaskEventMonitor object to look and notify if found * @return true if a monitor has been found and notification has been performed, false otherwise */ private boolean lookAndNotifyMonitor(RMEventMonitor monitor) { RMEventMonitor monitorToNotify = this.getAndRemoveMonitor(monitor); if (monitorToNotify != null) { synchronized (monitorToNotify) { //monitor exists, but maybe created by a waiter that has reached timeout //so check if it has been timeouted if (!monitorToNotify.isTimeouted()) { notifyMonitor(monitorToNotify); return true; } } } return false; } /** * Notify threads, if any that wait for a specific event * * @param monitor TaskEventMonitor object to look and notify if found * @return true if a monitor has been found and notification has been performed, false otherwise */ private boolean lookAndNotifyMonitor(NodeEventMonitor monitor) { NodeEventMonitor monitorToNotify = (NodeEventMonitor) this.getAndRemoveMonitor(monitor); if (monitorToNotify != null) { synchronized (monitorToNotify) { //monitor exists, but maybe created by a waiter that has reached timeout //so check if it has been timeouted if (!monitorToNotify.isTimeouted()) { monitorToNotify.setNodeUrl(monitor.getNodeUrl()); monitorToNotify.setNodeEvent(monitor.getNodeEvent()); notifyMonitor(monitorToNotify); return true; } } } return false; } /** * Return an EventMonitor that is currently used to wait for an event, or null if * this event is awaited by no one. * @param monitor EventMonitor Object representing Event to look for. * @return an eventMonitor object to notify, or null. */ private RMEventMonitor getAndRemoveMonitor(RMEventMonitor monitor) { if (eventsMonitors.contains(monitor)) { return eventsMonitors.remove(eventsMonitors.indexOf(monitor)); } return null; } /** * Returns a monitor used to wait for a specific event that hasn't yet occurred. * If there is not yet a monitor for this event, EventMonitor passed in parameter is * used as Monitor object for this event. * @param monitor representing event to wait for. * @return an EventMonitorJob to use as waiting Monitor. */ private RMEventMonitor getMonitor(RMEventMonitor monitor) { if (!eventsMonitors.contains(monitor)) { eventsMonitors.add(monitor); return monitor; } else { return eventsMonitors.get(eventsMonitors.indexOf(monitor)); } } /** * Notify an EventMonitor object, i.e resume threads that have perform * a wait on EventMonitor object passed in parameter. * @param monitorToNotify EventMonitor to notify. */ private void notifyMonitor(RMEventMonitor monitorToNotify) { synchronized (monitorToNotify) { monitorToNotify.setEventOccured(); monitorToNotify.notify(); } } //---------------------------------------------------------------// //private methods // these method MUST NOT be called from a synchronized(this) block //---------------------------------------------------------------// private void waitWithMonitor(RMEventMonitor monitor, long timeout) throws ProActiveTimeoutException { TimeoutAccounter counter = TimeoutAccounter.getAccounter(timeout); synchronized (monitor) { monitor.setTimeouted(false); while (!counter.isTimeoutElapsed()) { if (monitor.eventOccured()) return; try { monitor.wait(counter.getRemainingTimeout()); } catch (InterruptedException e) { //spurious wake-up, nothing to do e.printStackTrace(); } } monitor.setTimeouted(true); } throw new ProActiveTimeoutException("timeout elapsed"); } public synchronized void dumpEvents() { RMTHelper.log("RM events"); for (RMEventType e : stateEvents) { RMTHelper.log(e.toString()); } RMTHelper.log("RM node source events"); for (NodeSourceEventMonitor e : nodeSourcesEvent) { RMTHelper.log(e.toString()); } RMTHelper.log("RM node events"); for (NodeEventMonitor e : nodesEvent) { RMTHelper.log(e.toString()); } } public synchronized void flushEvents() { stateEvents.clear(); nodeSourcesEvent.clear(); nodesEvent.clear(); eventsMonitors.clear(); } }