package edu.washington.escience.myria.parallel.ipc;
import org.jboss.netty.buffer.ChannelBuffer;
import org.jboss.netty.buffer.ChannelBuffers;
import com.google.common.base.Preconditions;
/**
* All IPCMessages derived from this class.
* */
public interface IPCMessage {
/**
* Header of IPCMessages in serialized version.
* */
enum Header {
/***/
EOS,
BOS,
CONNECT,
DISCONNECT,
PING,
DATA
}
/**
* Meta IPCMessages, used inside the IPC module only. It has the following cases: EOS, BOS, CONNECT, DISCONNECT, PING.
* */
abstract class Meta implements IPCMessage {
/**
* EOS.
* */
static final Meta EOS =
new Meta() {
private final ChannelBuffer serializeValue =
ChannelBuffers.wrappedBuffer(new byte[] {(byte) Header.EOS.ordinal()});
@Override
public ChannelBuffer serialize() {
return serializeValue;
}
@Override
public String toString() {
return "IPCMessage.Meta.EOS";
}
};
/**
* DISCONNECT.
* */
static final Meta DISCONNECT =
new Meta() {
private final ChannelBuffer serializeValue =
ChannelBuffers.wrappedBuffer(new byte[] {(byte) Header.DISCONNECT.ordinal()});
@Override
public ChannelBuffer serialize() {
return serializeValue;
}
@Override
public String toString() {
return "IPCMessage.Meta.DISCONNECT";
}
};
/**
* BOS.
* */
static final class BOS extends Meta {
/**
* stream id.
* */
private final long streamID;
/**
* serialize value.
* */
private final ChannelBuffer serializeValue;
/**
* @param streamID stream id.
* */
public BOS(final long streamID) {
this.streamID = streamID;
ChannelBuffer bb = ChannelBuffers.buffer(1 + Long.SIZE / Byte.SIZE);
bb.writeByte((byte) Header.BOS.ordinal());
bb.writeLong(streamID);
serializeValue = ChannelBuffers.unmodifiableBuffer(bb);
}
/**
* @return the stream id.
* */
long getStreamID() {
return streamID;
}
@Override
public ChannelBuffer serialize() {
return serializeValue.duplicate();
}
/**
* @return De-serialize the BOS message.
* @param bb serialized data.
* */
public static BOS deSerialize(final ChannelBuffer bb) {
return new BOS(bb.readLong());
}
@Override
public String toString() {
return "IPCMessage.Meta.BOS(" + streamID + ")";
}
}
/**
* CONNECT.
* */
static final class CONNECT extends Meta {
/**
* remote ID.
* */
private final int remoteID;
/**
* serialize value.
* */
private final ChannelBuffer serializeValue;
/**
* @param remoteID the remote IPC ID.
* */
public CONNECT(final int remoteID) {
this.remoteID = remoteID;
ChannelBuffer bb = ChannelBuffers.buffer(1 + Integer.SIZE / Byte.SIZE);
bb.writeByte((byte) Header.CONNECT.ordinal());
bb.writeInt(remoteID);
serializeValue = ChannelBuffers.unmodifiableBuffer(bb);
}
/**
* @return get the remote IPC ID.
* */
public int getRemoteID() {
return remoteID;
}
@Override
public ChannelBuffer serialize() {
return serializeValue.duplicate();
}
/**
* @return Deserialize the CONNECT message.
* @param bb serialized data.
* */
public static CONNECT deSerialize(final ChannelBuffer bb) {
return new CONNECT(bb.readInt());
}
@Override
public String toString() {
return "IPCMessage.Meta.CONNECT(" + remoteID + ")";
}
}
/**
* PING.
* */
static final Meta PING =
new Meta() {
private final ChannelBuffer serializeValue =
ChannelBuffers.wrappedBuffer(new byte[] {(byte) Header.PING.ordinal()});
@Override
public ChannelBuffer serialize() {
return serializeValue;
}
@Override
public String toString() {
return "IPCMessage.Meta.PING";
}
};
/**
* Serialize the message.
*
* @return serialize result.
* */
public abstract ChannelBuffer serialize();
/**
* @return deserialize meta messages
* @param bb serialized data.
* */
public static Meta deSerialize(final ChannelBuffer bb) {
byte type = bb.readByte();
if (type == Header.BOS.ordinal()) {
return BOS.deSerialize(bb);
} else if (type == Header.CONNECT.ordinal()) {
return CONNECT.deSerialize(bb);
} else if (type == Header.DISCONNECT.ordinal()) {
return DISCONNECT;
} else if (type == Header.EOS.ordinal()) {
return EOS;
} else if (type == Header.PING.ordinal()) {
return PING;
} else {
return null;
}
}
}
/**
* Unit of IPC transmission.
*
* @param <PAYLOAD> the type of payload. Currently, this PAYLOAD could only be: TransportMessage.QUERY,
* TransportMessage.CONTROL.
* */
public class Data<PAYLOAD> implements IPCMessage {
/**
* the payload.
* */
private final PAYLOAD p;
/**
* the source remote id.
* */
private final int sourceRemote;
/**
* @param sourceRemote the source remote id
* @param p the payload.
* */
private Data(final int sourceRemote, final PAYLOAD p) {
this.p = p;
this.sourceRemote = sourceRemote;
}
/**
* @return the payload
* */
public PAYLOAD getPayload() {
return p;
}
/**
* @return the source remote id.
* */
public int getRemoteID() {
return sourceRemote;
}
/**
* serialize head.
* */
static final ChannelBuffer SERIALIZE_HEAD =
ChannelBuffers.wrappedBuffer(new byte[] {(byte) Header.DATA.ordinal()});
/**
* @param sourceRemote the source remote id.
* @param maybePayload either a paylod or a Data instance.
* @param <PAYLOAD> the payload type.
* @return the wrapped Data message.
* */
@SuppressWarnings("unchecked")
public static <PAYLOAD> Data<PAYLOAD> wrap(final int sourceRemote, final Object maybePayload) {
if (maybePayload instanceof Data) {
return (Data<PAYLOAD>) maybePayload;
} else {
return new Data<PAYLOAD>(sourceRemote, (PAYLOAD) maybePayload);
}
}
@Override
public String toString() {
return String.format("IPCMessage.Data(from:%1$d,payload:%2$s)", sourceRemote, p);
}
}
/**
* Unit of IPC Stream.
*
* @param <PAYLOAD> the type of payload. Currently, this PAYLOAD could only be TupleBatch.
* */
public final class StreamData<PAYLOAD> extends Data<PAYLOAD> {
/**
* the stream ID.
* */
private final long streamID;
/**
* @param sourceRemote the source remote ID.
* @param streamID stream ID.
* @param p the payload.
* */
private StreamData(final int sourceRemote, final long streamID, final PAYLOAD p) {
super(sourceRemote, Preconditions.checkNotNull(p));
this.streamID = streamID;
}
/**
* @param sourceRemote the source remote ID.
* @param streamID stream ID.
* */
private StreamData(final int sourceRemote, final long streamID) {
super(sourceRemote, null);
this.streamID = streamID;
}
/**
* @return the stream ID.
* */
public long getStreamID() {
return streamID;
}
/**
* @param <PAYLOAD> the payload type.
* @param sourceRemote the source remote ID.
* @param streamID stream ID.
* @return an EOS message.
* */
public static <PAYLOAD> StreamData<PAYLOAD> eos(final int sourceRemote, final long streamID) {
return new StreamData<PAYLOAD>(sourceRemote, streamID);
}
/**
* @param sourceRemote the source remote id.
* @param maybePayload either a paylod or a StreamData instance.
* @param <PAYLOAD> the payload type.
* @param streamID stream ID.
* @return the wrapped StreamData message.
* */
@SuppressWarnings("unchecked")
public static <PAYLOAD> StreamData<PAYLOAD> wrap(
final int sourceRemote, final long streamID, final Object maybePayload) {
if (maybePayload instanceof StreamData) {
return (StreamData<PAYLOAD>) maybePayload;
} else {
return new IPCMessage.StreamData<PAYLOAD>(sourceRemote, streamID, (PAYLOAD) maybePayload);
}
}
@Override
public String toString() {
return String.format(
"IPCMessage.StreamData(from:%1$d,stream:%2$d,payload:%3$s)",
getRemoteID(),
streamID,
getPayload());
}
}
}