/**
* This file is part of the Kompics P2P Framework.
*
* Copyright (C) 2009 Swedish Institute of Computer Science (SICS)
* Copyright (C) 2009 Royal Institute of Technology (KTH)
*
* Kompics is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
package se.sics.gvod.common.msgs;
import io.netty.buffer.ByteBuf;
import se.sics.gvod.net.VodAddress;
import se.sics.gvod.common.UtilityVod;
import se.sics.gvod.net.VodMsgFrameDecoder;
import se.sics.gvod.net.msgs.RewriteableMsg;
import se.sics.gvod.net.msgs.RewriteableRetryTimeout;
import se.sics.gvod.net.msgs.ScheduleRetryTimeout;
import se.sics.gvod.net.util.UserTypesEncoderFactory;
import se.sics.gvod.timer.OverlayTimeout;
import se.sics.gvod.timer.ScheduleTimeout;
import se.sics.gvod.timer.TimeoutId;
import se.sics.gvod.timer.UUID;
/**
*
* This msg is a request and response for a subpiece, with a
* supplied ackId and the delay will be measured for the uplink
* (Response msg). The Request sends back the delay for the previous
* Response.
*
* @author jdowling
*/
public class DataMsg {
public static class Request extends DirectMsgNetty.Request {
private final TimeoutId ackId;
private final int piece;
private final int subpieceOffset;
private final long delay;
public Request(VodAddress self, VodAddress destination,
TimeoutId ackId, int piece, int subpieceOffset,
long delay) {
super(self, destination);
if (ackId == null) {
this.ackId = new UUID(0);
} else {
this.ackId = ackId;
}
this.piece = piece;
this.subpieceOffset = subpieceOffset;
this.delay = delay;
}
public int getSubpieceOffset() {
return subpieceOffset;
}
public int getPiece() {
return piece;
}
public TimeoutId getAckId() {
return ackId;
}
public long getDelay() {
return delay;
}
@Override
public byte getOpcode() {
return VodMsgFrameDecoder.D_REQUEST;
}
@Override
public int getSize() {
return super.getHeaderSize()
+ 4 /*ackId*/
+ 4 /*piece*/
+ 4 /*subpiece*/
+ 8 /*delay*/;
}
@Override
public ByteBuf toByteArray() throws MessageEncodingException {
ByteBuf buffer = createChannelBufferWithHeader();
buffer.writeInt(ackId.getId());
buffer.writeInt(piece);
buffer.writeInt(subpieceOffset);
buffer.writeLong(delay);
return buffer;
}
@Override
public RewriteableMsg copy() {
Request r = new Request(vodSrc, vodDest, ackId, piece, subpieceOffset, delay);
r.setTimeoutId(timeoutId);
return r;
}
}
public static class Response extends DirectMsgNetty.Response {
private final TimeoutId ackId;
private final byte[] sp;
private final int spOffset;
private final int p;
private final int cwSz;
private final long t;
public Response(VodAddress source, VodAddress destination,
TimeoutId timeoutId,
TimeoutId ackId, byte[] subpiece, int subpieceOffset, int piece,
int comWinSize, long time) {
super(source, destination, timeoutId);
if (ackId == null) {
throw new IllegalArgumentException("AckId was null");
}
this.ackId = ackId;
this.sp = subpiece;
this.spOffset = subpieceOffset;
this.p = piece;
this.cwSz = comWinSize;
this.t = time;
}
public long getTime() {
return t;
}
public TimeoutId getAckId() {
return ackId;
}
public int getComWinSize() {
return cwSz;
}
public byte[] getSubpiece() {
return sp;
}
public int getSubpieceOffset() {
return spOffset;
}
public int getPiece() {
return p;
}
@Override
public byte getOpcode() {
return VodMsgFrameDecoder.D_RESPONSE;
}
@Override
public int getSize() {
int spSz = 0;
if (sp != null) {
spSz = sp.length;
}
return super.getHeaderSize()
// + +UserTypesEncoderFactory.TimeoutId_LEN
+ 4 /*timeoutId*/
+ spSz
+ 4 /*nb*/
+ 4 /*p*/
+ 4 /*cwSz*/
+ 8 /*time*/;
}
@Override
public ByteBuf toByteArray() throws MessageEncodingException {
ByteBuf buf = createChannelBufferWithHeader();
buf.writeInt(ackId.getId());
UserTypesEncoderFactory.writeArrayBytes(buf, sp);
buf.writeInt(spOffset);
buf.writeInt(p);
buf.writeInt(cwSz);
buf.writeLong(t);
return buf;
}
@Override
public RewriteableMsg copy() {
return new Response(vodSrc, vodDest, timeoutId, ackId, sp, spOffset, p, cwSz, t);
}
}
/**
* No point re-sending the ackTimeout with a new DataRequest.
*/
public static class DataRequestTimeout extends RewriteableRetryTimeout {
private final VodAddress dest;
private final int piece;
private final int subpiece;
public DataRequestTimeout(ScheduleRetryTimeout request, Request requestMsg) {
super(request, requestMsg, requestMsg.getVodSource().getOverlayId());
this.dest = requestMsg.getVodDestination();
this.piece = requestMsg.getPiece();
this.subpiece = requestMsg.getSubpieceOffset();
}
public VodAddress getDest() {
return dest;
}
public int getPiece() {
return piece;
}
public int getSubpiece() {
return subpiece;
}
}
/**
* TODO - these messages are huge. Turn into BitSet.
*/
public static class PieceNotAvailable extends DirectMsgNetty.Oneway {
private final byte[] availableChunks;
private final UtilityVod utility;
private final int piece;
private final byte[][] availablePieces;
public PieceNotAvailable(VodAddress source, VodAddress destination,
byte[] availableChunks, UtilityVod utility, int piece,
byte[][] availablePieces) {
super(source, destination);
this.availableChunks = availableChunks;
this.utility = new UtilityVod(utility.getChunk(), utility.getPiece(), utility.getOffset());
this.piece = piece;
this.availablePieces = availablePieces;
}
public byte[] getAvailableChunks() {
return availableChunks;
}
public UtilityVod getUtility() {
return utility;
}
public int getPiece() {
return piece;
}
public byte[][] getAvailablePieces() {
return availablePieces;
}
@Override
public byte getOpcode() {
return VodMsgFrameDecoder.PIECE_NOT_AVAILABLE;
}
@Override
public int getSize() {
int sz = getHeaderSize()
+ UserTypesEncoderFactory.getArraySize(availableChunks)
+ UserTypesEncoderFactory.UTILITY_LEN
+ 4 /*piece*/
+ UserTypesEncoderFactory.getArrayArraySize(availablePieces);
return sz;
}
@Override
public ByteBuf toByteArray() throws MessageEncodingException {
ByteBuf buffer = createChannelBufferWithHeader();
UserTypesEncoderFactory.writeArrayBytes(buffer, availableChunks);
UserTypesEncoderFactory.writeUtility(buffer, utility);
buffer.writeInt(piece);
UserTypesEncoderFactory.writeArrayArrayBytes(buffer, availablePieces);
return buffer;
}
@Override
public RewriteableMsg copy() {
PieceNotAvailable p = new PieceNotAvailable(vodSrc, vodDest, availableChunks,
utility, piece, availablePieces);
p.setTimeoutId(timeoutId);
return p;
}
}
public static class Saturated extends DirectMsgNetty.Oneway {
private final int subpiece;
private final int comWinSize;
public Saturated(VodAddress source, VodAddress destination, int subpiece,
int comWinSize) {
super(source, destination);
this.subpiece = subpiece;
this.comWinSize = comWinSize;
}
public int getComWinSize() {
return comWinSize;
}
public int getSubpiece() {
return subpiece;
}
@Override
public byte getOpcode() {
return VodMsgFrameDecoder.SATURATED;
}
@Override
public int getSize() {
return super.getHeaderSize()
+ 4 /* subpiece */
+ 4 /* comWinSize */;
}
@Override
public ByteBuf toByteArray() throws MessageEncodingException {
ByteBuf buf = createChannelBufferWithHeader();
buf.writeInt(subpiece);
buf.writeInt(comWinSize);
return buf;
}
@Override
public RewriteableMsg copy() {
return new Saturated(vodSrc, vodDest, subpiece, comWinSize);
}
}
public static class Ack extends DirectMsgNetty.Response {
private final long delay;
public Ack(VodAddress source, VodAddress destination, TimeoutId timeoutId,
long delay) {
super(source, destination, timeoutId);
this.delay = delay;
}
public TimeoutId getAckId() {
return timeoutId;
}
public long getDelay() {
return delay;
}
@Override
public byte getOpcode() {
return VodMsgFrameDecoder.ACK;
}
@Override
public int getSize() {
return super.getHeaderSize()
+ 8 /*delay*/;
}
@Override
public ByteBuf toByteArray() throws MessageEncodingException {
ByteBuf buf = createChannelBufferWithHeader();
buf.writeLong(delay);
return buf;
}
@Override
public RewriteableMsg copy() {
return new Ack(vodSrc, vodDest, timeoutId, delay);
}
}
public static class AckTimeout extends OverlayTimeout {
private final VodAddress peer;
public AckTimeout(ScheduleTimeout request, VodAddress peer, int overlayId) {
super(request, overlayId);
this.peer = peer;
}
public VodAddress getPeer() {
return peer;
}
}
public static class HashRequest extends DirectMsgNetty.Request {
private final int chunk;
private final int part;
public HashRequest(VodAddress source, VodAddress destination, int chunk) {
this(source, destination, chunk, 0);
}
public HashRequest(VodAddress source, VodAddress destination,
int chunk, int part) {
super(source, destination);
this.chunk = chunk;
this.part = part;
}
public int getChunk() {
return chunk;
}
public int getPart() {
return part;
}
@Override
public byte getOpcode() {
return VodMsgFrameDecoder.HASH_REQUEST;
}
@Override
public int getSize() {
return super.getHeaderSize()
+ 2 /*chunk*/
+ 1 /*part*/;
}
@Override
public ByteBuf toByteArray() throws MessageEncodingException {
ByteBuf buf = createChannelBufferWithHeader();
UserTypesEncoderFactory.writeUnsignedintAsTwoBytes(buf, chunk);
UserTypesEncoderFactory.writeUnsignedintAsOneByte(buf, part);
return buf;
}
@Override
public RewriteableMsg copy() {
HashRequest hr = new HashRequest(vodSrc, vodDest, chunk, part);
hr.setTimeoutId(timeoutId);
return hr;
}
}
public static class HashResponse extends DirectMsgNetty.Response {
private final int chunk;
private final byte[] hashes;
private final int part;
private final int numParts;
public HashResponse(VodAddress source, VodAddress destination, TimeoutId timeoutId,
int chunk, byte[] hashes, int part, int numParts) {
super(source, destination, timeoutId);
this.chunk = chunk;
this.hashes = hashes;
this.part = part;
this.numParts = numParts;
}
public int getChunk() {
return chunk;
}
public byte[] getHashes() {
return hashes;
}
public int getPart() {
return part;
}
public int getNumParts() {
return numParts;
}
@Override
public byte getOpcode() {
return VodMsgFrameDecoder.HASH_RESPONSE;
}
@Override
public int getSize() {
int size = getHeaderSize()
+ 2 /*chunk*/
+ UserTypesEncoderFactory.getArraySize(hashes)
+ 1 /*part*/
+ 1 /*num parts*/;
return size;
}
@Override
public ByteBuf toByteArray() throws MessageEncodingException {
ByteBuf buf = createChannelBufferWithHeader();
UserTypesEncoderFactory.writeUnsignedintAsTwoBytes(buf, chunk);
UserTypesEncoderFactory.writeArrayBytes(buf, hashes);
UserTypesEncoderFactory.writeUnsignedintAsOneByte(buf, part);
UserTypesEncoderFactory.writeUnsignedintAsOneByte(buf, numParts);
return buf;
}
@Override
public RewriteableMsg copy() {
return new HashResponse(vodSrc, vodDest, timeoutId, chunk, hashes, part, numParts);
}
}
public static class HashTimeout extends RewriteableRetryTimeout {
private final int chunk;
private final VodAddress peer;
private final int part;
public HashTimeout(ScheduleRetryTimeout srt, DataMsg.HashRequest requestMsg,
int chunk, VodAddress peer, int part) {
super(srt, requestMsg, requestMsg.getVodSource().getOverlayId());
this.chunk = chunk;
this.peer = peer;
this.part = part;
}
public int getChunk() {
return chunk;
}
public VodAddress getPeer() {
return peer;
}
public int getPart() {
return part;
}
}
}