package ibis.ipl.impl.multi; import ibis.ipl.Ibis; import ibis.ipl.IbisIdentifier; import ibis.ipl.ReadMessage; import ibis.ipl.ReceivePort; import ibis.ipl.SendPort; import ibis.ipl.WriteMessage; import ibis.util.ThreadPool; import java.io.IOException; import java.util.HashMap; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class MultiNameResolver { private static final Logger logger = LoggerFactory.getLogger(MultiNameResolver.class); private final MultiIbis ibis; private final String ibisName; private ReceivePort requestListenPort; private ReceivePort replyListenPort; private SendPort replyPort; private SendPort requestPort; private HashMap<Integer, IbisIdentifier> resolveQueue = new HashMap<Integer, IbisIdentifier>(); private boolean quit = false; private static final String resolvePortName = "ibis.multi.name.resolve"; private static final String replyPortName = "ibis.multi.name.resolveReply"; private static final byte OPP_REPLY = 1; private static final byte OPP_REQUEST = 2; private static final byte OPP_QUIT = 0; public MultiNameResolver(MultiIbis multiIbis, String ibisName) throws IOException { this.ibis = multiIbis; this.ibisName = ibisName; ibis.resolverMap.put(ibisName, this); Ibis subIbis = ibis.subIbisMap.get(ibisName); requestListenPort = subIbis.createReceivePort(MultiIbis.resolvePortType, resolvePortName); requestListenPort.enableConnections(); replyListenPort = subIbis.createReceivePort(MultiIbis.resolvePortType, replyPortName); replyListenPort.enableConnections(); replyPort = subIbis.createSendPort(MultiIbis.resolvePortType); requestPort = subIbis.createSendPort(MultiIbis.resolvePortType); if (logger.isDebugEnabled()) { logger.debug("Started MultiNameResolver for: " + ibisName); } ThreadPool.createNew(new RequestHandler(), "Request Listener: " + ibisName); ThreadPool.createNew(new ReplyHandler(), "Reply Listener: " + ibisName); } private void waitForId() { // Wait until we have an id set to share if (logger.isDebugEnabled()) { logger.debug("Waiting for id:" + ibisName); } while (ibis.id == null) { synchronized (this) { try { wait(); } catch (InterruptedException e) { // Ignored } } } if (logger.isDebugEnabled()) { logger.debug("Got id:" + ibisName); } } private class ReplyHandler implements Runnable { public void run() { waitForId(); do { try { if (logger.isDebugEnabled()) { logger.debug("ReplyHandler running for: " + ibisName); } ReadMessage readMessage; readMessage = replyListenPort.receive(); if (logger.isDebugEnabled()) { logger.debug("ReplyHandler read message for: " + ibisName); } byte operation = readMessage.readByte(); switch (operation) { case OPP_REPLY: if (logger.isDebugEnabled()) { logger.debug("Received Reply For: " + ibisName); } int hashCode = readMessage.readInt(); MultiIbisIdentifier id = (MultiIbisIdentifier) readMessage.readObject(); readMessage.finish(); if (logger.isDebugEnabled()) { logger.debug("Setting Resolved for: " + ibisName + " id: " + id); } ibis.resolved(id); if (logger.isDebugEnabled()) { logger.debug("Locking for: " + ibisName); } synchronized (resolveQueue) { IbisIdentifier toResolve = resolveQueue.remove(new Integer(hashCode)); synchronized(toResolve) { if (logger.isDebugEnabled()) { logger.debug("Notifying for resolution: " + ibisName + " on: " + this); } if (logger.isDebugEnabled()) { logger.debug("Notifying for resolution: " + ibisName + " on: " + this); } toResolve.notifyAll(); } } break; case OPP_QUIT: if (logger.isDebugEnabled()) { logger.debug("Resolver quitting for: " + ibisName); } readMessage.finish(); quit = true; break; default: if (logger.isDebugEnabled()) { logger.debug("Unknown request for: " + ibisName); } readMessage.finish(); break; } } catch (IOException e) { // TODO What do we do here now? logger.error("Got IOException while resolving: " + e); e.printStackTrace(); } catch (ClassNotFoundException e) { // TODO What do we do here now? logger.error("Got ClassNotFoundException while resolving: " + e); e.printStackTrace(); } } while(!quit); } } private class RequestHandler implements Runnable { public void run() { waitForId(); do { try { if (logger.isDebugEnabled()) { logger.debug("Resolver running for: " + ibisName); } ReadMessage readMessage; readMessage = requestListenPort.receive(); if (logger.isDebugEnabled()) { logger.debug("Resolver read message for: " + ibisName); } byte operation = readMessage.readByte(); switch (operation) { case OPP_REQUEST: if (logger.isDebugEnabled()) { logger.debug("Processing Request for: " + ibisName); } int hashCode = readMessage.readInt(); IbisIdentifier requestor = readMessage.origin().ibisIdentifier(); readMessage.finish(); if (logger.isDebugEnabled()) { logger.debug("Sending Reply For: " + ibisName + " from: " + requestor + " id:" + ibis.id); } replyPort.connect(requestor, replyPortName); WriteMessage sendMessage = replyPort.newMessage(); sendMessage.writeByte(OPP_REPLY); sendMessage.writeInt(hashCode); sendMessage.writeObject(ibis.id); sendMessage.finish(); if (logger.isDebugEnabled()) { logger.debug("Disconnecting Reply For: " + ibisName + " from: " + requestor); } replyPort.disconnect(requestor, replyPortName); if (logger.isDebugEnabled()) { logger.debug("Reply Complete for: " + ibisName + " from: " + requestor); } break; case OPP_QUIT: readMessage.finish(); if (logger.isDebugEnabled()) { logger.debug("Resolver quitting for: " + ibisName); } quit = true; break; default: if (logger.isDebugEnabled()) { logger.debug("Unknown request for: " + ibisName); } readMessage.finish(); break; } } catch (IOException e) { // TODO What do we do here now? logger.error("Got IOException while resolving: " + e); e.printStackTrace(); } } while(!quit); } } public static void quit() { // TODO Wake up all threads. } public void resolve(IbisIdentifier toResolve, String ibisName) throws IOException { if (logger.isDebugEnabled()) { logger.debug("Making Resolve Request for: " + ibisName); } Integer id = new Integer(toResolve.hashCode()); synchronized (resolveQueue) { // Make sure we don't collide while (resolveQueue.get(id) != null) { try { resolveQueue.wait(); } catch (InterruptedException e) { // Ignored } } resolveQueue.put(id, toResolve); } synchronized (toResolve) { this.requestPort.connect(toResolve, resolvePortName); if (logger.isDebugEnabled()) { logger.debug("Sending Request for: " + ibisName); } WriteMessage writeMessage = this.requestPort.newMessage(); writeMessage.writeByte(OPP_REQUEST); writeMessage.writeInt(toResolve.hashCode()); if (logger.isDebugEnabled()) { logger.debug("Finishing Request for: " + ibisName); } writeMessage.finish(); if (logger.isDebugEnabled()) { logger.debug("Disconnecting Request for: " + ibisName); } this.requestPort.disconnect(toResolve, resolvePortName); while (!ibis.isResolved(toResolve)) { try { // Wait for the resolution to finish. if (logger.isDebugEnabled()) { logger.debug("Waiting For Resolution For: " + ibisName + " on: " + this); } toResolve.wait(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } if (logger.isDebugEnabled()) { logger.debug("Resolution Complete for: " + ibisName); } } } }