//---------------------------------------------------------------------------
// Copyright 2006-2009
// Dan Roozemond, d.a.roozemond@tue.nl, (TU Eindhoven, Netherlands)
// Peter Horn, horn@math.uni-kassel.de (University Kassel, Germany)
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//---------------------------------------------------------------------------
package org.symcomp.spsd;
import org.symcomp.openmath.*;
import org.symcomp.scscp.ProcedureCallHandler;
import org.symcomp.scscp.SCSCPClient;
import org.symcomp.notification.NotificationReceiver;
import org.symcomp.notification.Notification;
import org.symcomp.notification.NotificationCenter;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.HashMap;
import java.util.Collection;
/**
* is a specialized ProcedureCallHandler prpared for distribution of
* computations.
*/
public abstract class AbstractSPSDHandler extends ProcedureCallHandler implements NotificationReceiver {
protected BlockingQueue<SCSCPClient> workers;
protected OpenMathBase[] results;
protected HashMap<String, Integer> positions;
public OMSymbol getServiceName() {
return new OMSymbol("spsd", getServiceNameStr());
}
public AbstractSPSDHandler() {
workers = new ArrayBlockingQueue<SCSCPClient>(100);
NotificationCenter.getNC().register(this, "ComputationFinished");
}
public int setWorkers(Collection<SCSCPClient> workers) {
for (SCSCPClient s : workers) {
this.workers.offer(s);
}
return workers.size();
}
//To be implemented by the actual handlers
public abstract void initSPSDComputation(OpenMathBase omoo) throws OpenMathException;
public abstract int getSPSDNumTasks();
public abstract OpenMathBase getSPSDTask(int i);
//Where THINGS are going on
public synchronized OpenMathBase handlePayload(OpenMathBase omoo)
throws OpenMathException {
// check whether there are überhaupt any workers
if (0 == this.workers.size()) {
throw new OpenMathException("SPSD: No systems given.");
}
int numworkers = this.workers.size();
//Initialize computation
this.initSPSDComputation(omoo);
//Initialize results and position arrays
int numTasks = getSPSDNumTasks();
this.results = new OpenMathBase[numTasks];
this.positions = new HashMap<String, Integer>();
//Perforum the computation
SCSCPClient client = null;
for (int i = 0; i < numTasks; ++i) {
//Get a client
try {
client = workers.take();
} catch (InterruptedException ignored) { }
//Start a computation
assert client != null;
String token = client.compute(getSPSDTask(i));
//Put the token into the positions hashmap
this.positions.put(token, i);
}
//We are done, but to ensure that we have consumed all results
//we wait till all workers were available.
for (int i = 1; i <= numworkers; i++) {
try {
workers.take();
} catch (InterruptedException ignored) { }
}
//Now we are done, and we dare to return the result.
return (new OMSymbol("list1", "list")).apply(results);
}
public void receiveNotification(Notification notification) {
if (null == this.positions)
return;
if (notification.getMessage().equals("ComputationFinished")) {
try {
//Parse notification
String token = (String) notification.getData().get("token");
OpenMathBase result = (OpenMathBase) notification.getData().get("result");
SCSCPClient client = (SCSCPClient) notification.getSender();
//EVIL HACK, need to improve the Notification stuff
if (client.getServiceName().equals("SPSD")) return;
//Store result
Integer p = (Integer) this.positions.get(token);
if (null == p)
return;
OpenMathBase res = result.deOMObject();
synchronized (results) {
this.results[p] = res;
}
//Give worker back
workers.offer(client);
} catch(Exception ignored) {}
} else {
throw new RuntimeException("Unexpected Notification");
}
}
}