/*
* 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.cleaning;
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import org.apache.log4j.Logger;
import org.objectweb.proactive.Body;
import org.objectweb.proactive.RunActive;
import org.objectweb.proactive.Service;
import org.objectweb.proactive.core.body.request.Request;
import org.objectweb.proactive.core.util.wrapper.BooleanWrapper;
import org.objectweb.proactive.extensions.annotation.ActiveObject;
import org.ow2.proactive.resourcemanager.core.RMCore;
import org.ow2.proactive.resourcemanager.core.properties.PAResourceManagerProperties;
import org.ow2.proactive.resourcemanager.rmnode.RMNode;
/**
* This class is responsible for the node cleaning.
* It does it in parallel in a dedicated thread pool.
*/
@ActiveObject
public class NodesCleaner implements RunActive {
/** class' logger */
private static final Logger logger = Logger.getLogger(NodesCleaner.class);
private ExecutorService scriptExecutorThreadPool;
/** RMCore reference to be able to set nodes free after the cleaning procedure */
private RMCore rmcore;
/** PA Constructor */
public NodesCleaner() {
}
public NodesCleaner(RMCore rmcore) {
this.rmcore = rmcore;
this.scriptExecutorThreadPool = Executors.newFixedThreadPool(PAResourceManagerProperties.RM_CLEANING_MAX_THREAD_NUMBER.getValueAsInt());
}
/**
* Cleans nodes in parallel for the nodes specified.
*
* @param nodes to be cleaned
* @return true if all the nodes were freed, false if error occurs on one of the node (it will be marked as down in this case)
*/
public BooleanWrapper cleanAndRelease(List<RMNode> nodes) {
List<Callable<Boolean>> cleaners = new LinkedList<>();
for (RMNode node : nodes) {
logger.debug("Cleaning the node " + node.getNodeURL());
cleaners.add(new NodeCleaner(node));
}
try {
Collection<Future<Boolean>> cleanNodes = scriptExecutorThreadPool.invokeAll(cleaners);
int index = 0;
for (Future<Boolean> cleanNode : cleanNodes) {
RMNode node = nodes.get(index);
if (!cleanNode.isCancelled()) {
Boolean isClean = null;
try {
isClean = cleanNode.get();
if (!isClean.booleanValue()) {
logger.warn("Cannot clean the node " + node.getNodeURL());
rmcore.setDownNode(node.getNodeURL());
} else {
logger.debug("The node " + node.getNodeURL() + " has been successfully cleaned");
}
} catch (ExecutionException e) {
logger.warn("Cannot clean the node " + node.getNodeURL(), e);
rmcore.setDownNode(node.getNodeURL());
}
} else {
logger.warn("Cannot clean the node " + node.getNodeURL());
rmcore.setDownNode(node.getNodeURL());
}
index++;
}
// if we had any error while cleaning a node, this node would have been already marked as down
// in this case rmcore.setFreeNodes() will return false
return rmcore.setFreeNodes(nodes);
} catch (InterruptedException e) {
logger.error("", e);
}
return new BooleanWrapper(false);
}
/**
* Method controls the execution of every request.
* Tries to keep this active object alive in case of any exception.
*/
public void runActivity(Body body) {
Service service = new Service(body);
while (body.isActive()) {
Request request = null;
try {
request = service.blockingRemoveOldest();
if (request != null) {
try {
service.serve(request);
} catch (Throwable e) {
logger.error("Cannot serve request: " + request, e);
}
}
} catch (InterruptedException e) {
logger.warn("runActivity interrupted", e);
}
}
}
}