package org.corfudb.protocols.wireprotocol;
import io.netty.buffer.ByteBuf;
import lombok.*;
import java.util.Arrays;
import java.util.Map;
import java.util.UUID;
import java.util.function.Function;
import java.util.stream.Collectors;
/**
* Created by mwei on 9/15/15.
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class CorfuMsg {
/**
* Marker field value, should equal 0xC0FC0FC0
*/
final static int markerField = 0xC0FC0FC0;
static Map<Byte, CorfuMsgType> typeMap =
Arrays.<CorfuMsgType>stream(CorfuMsgType.values())
.collect(Collectors.toMap(CorfuMsgType::asByte, Function.identity()));
/**
* The unique id of the client making the request
*/
UUID clientID;
/**
* The request id of this request/response
*/
long requestID;
/**
* The epoch of this request/response
*/
long epoch;
/**
* The underlying ByteBuf, if present.
*/
ByteBuf buf;
;
/**
* The type of message
*/
CorfuMsgType msgType;
/**
* Constructor which generates a message based only the message type.
* Typically used for generating error messages, since sendmessage will populate the rest of the fields.
*
* @param type The type of message to send.
*/
public CorfuMsg(CorfuMsgType type) {
this.msgType = type;
}
/* The wire format of the NettyCorfuMessage message is below:
markerField(1) | client ID(8) | request ID(8) | epoch(8) | type(1) |
*/
/**
* Take the given bytebuffer and deserialize it into a message.
*
* @param buffer The buffer to deserialize.
* @return The corresponding message.
*/
public static CorfuMsg deserialize(ByteBuf buffer) {
int marker = buffer.readInt();
if (marker != markerField) {
throw new RuntimeException("Attempt to deserialize a message which is not a CorfuMsg, "
+ "Marker = " + marker + " but expected 0xC0FC0FC0");
}
UUID clientID = new UUID(buffer.readLong(), buffer.readLong());
long requestID = buffer.readLong();
long epoch = buffer.readLong();
CorfuMsgType message = typeMap.get(buffer.readByte());
CorfuMsg msg = message.getConstructor().construct();
msg.clientID = clientID;
msg.requestID = requestID;
msg.epoch = epoch;
msg.msgType = message;
msg.fromBuffer(buffer);
msg.buf = buffer;
return msg;
}
/**
* Serialize the message into the given bytebuffer.
*
* @param buffer The buffer to serialize to.
*/
public void serialize(ByteBuf buffer) {
buffer.writeInt(markerField);
if (clientID == null) {
buffer.writeLong(0L);
buffer.writeLong(0L);
} else {
buffer.writeLong(clientID.getMostSignificantBits());
buffer.writeLong(clientID.getLeastSignificantBits());
}
buffer.writeLong(requestID);
buffer.writeLong(epoch);
buffer.writeByte(msgType.asByte());
}
/**
* Parse the rest of the message from the buffer. Classes that extend CorfuMsg
* should parse their fields in this method.
*
* @param buffer
*/
public void fromBuffer(ByteBuf buffer) {
// we don't do anything here since in the base message, no fields remain.
}
/**
* Copy the base fields over to this message
*/
public void copyBaseFields(CorfuMsg msg) {
this.clientID = msg.clientID;
this.epoch = msg.epoch;
this.requestID = msg.requestID;
}
/**
* Release the underlying buffer, if present.
*/
public void release() {
if (buf != null) {
buf.release();
}
}
}