/* * Galaxy * Copyright (c) 2012-2014, Parallel Universe Software Co. All rights reserved. * * This program and the accompanying materials are dual-licensed under * either the terms of the Eclipse Public License v1.0 as published by * the Eclipse Foundation * * or (per the licensee's choosing) * * under the terms of the GNU Lesser General Public License version 3.0 * as published by the Free Software Foundation. */ package co.paralleluniverse.galaxy.core; import co.paralleluniverse.common.collection.ConcurrentMapComplex; import co.paralleluniverse.galaxy.Cluster; import co.paralleluniverse.galaxy.cluster.NodeChangeListener; import co.paralleluniverse.galaxy.core.Message.LineMessage; import com.google.common.collect.HashMultimap; import com.google.common.collect.ImmutableSetMultimap; import com.google.common.collect.Multimap; import com.google.common.collect.Multimaps; import com.google.common.collect.SetMultimap; import java.util.Iterator; import java.util.Set; /** * This class is unused as it's insufficient to invalidate S lines whose owner has died. * @author pron */ class NodeDeathLayer implements Comm, NodeChangeListener, MessageReceiver { private final Comm comm; private final Cluster cluster; private MessageReceiver cache; private final ConcurrentMapComplex<Short, SetMultimap<Long, LineMessage>> pending = new ConcurrentMapComplex<Short, SetMultimap<Long, LineMessage>>() { @Override protected SetMultimap<Long, LineMessage> allocateElement() { SetMultimap<Long, LineMessage> mm = HashMultimap.create(); return Multimaps.synchronizedSetMultimap(mm); } @Override protected SetMultimap<Long, LineMessage> emptyElement() { return ImmutableSetMultimap.of(); } }; public NodeDeathLayer(Comm comm, Cluster cluster) { this.comm = comm; this.cluster = cluster; comm.setReceiver(this); cluster.addNodeChangeListener(this); } @Override public void setReceiver(MessageReceiver receiver) { cache = receiver; } public void addPending(LineMessage message) { short node = message.getNode(); if (node != -1) pending.getOrAllocate(node).put(message.getLine(), message); } public void removePending(LineMessage message) { Set<LineMessage> msgs = pending.get(message.getNode()).get(message.getLine()); for (Iterator<LineMessage> it = msgs.iterator(); it.hasNext();) { Message msg = it.next(); if (message.getType() == Message.Type.INVACK && msg.getType() == Message.Type.INV) it.remove(); else if (message.getType() == Message.Type.PUTX && (msg.getType() == Message.Type.GETX || msg.getType() == Message.Type.GET)) it.remove(); else if (message.getType() == Message.Type.PUT && msg.getType() == Message.Type.GET) it.remove(); } } @Override public void receive(Message message) { removePending((LineMessage)message); cache.receive(message); } @Override public void send(Message message) { try { comm.send(message); } catch (NodeNotFoundException e) { final Message response = genResponse((LineMessage)message); if (response != null) cache.receive(shortCircuitMessage(message.getNode(), response)); } } @Override public void nodeRemoved(short node) { final Multimap<Long, LineMessage> mm = pending.get(node); for (LineMessage m : mm.values()) { final Message response = genResponse(m); if (response != null) cache.receive(shortCircuitMessage(m.getNode(), response)); } pending.remove(node); } private Message genResponse(Message message) { switch (message.getType()) { case INV: return Message.INVACK((Message.INV)message); case GET: case GETX: return Message.CHNGD_OWNR((LineMessage)message, ((LineMessage)message).getLine(), (short) -1, false); default: return null; // don't send message } } @Override public void nodeAdded(short node) { } private Message shortCircuitMessage(short node, Message message) { message.setIncoming(); message.setNode(node); return message; } @Override public void nodeSwitched(short id) { throw new UnsupportedOperationException("Not supported yet."); } }