Skip to content

Commit

Permalink
Refactored tap message classes.
Browse files Browse the repository at this point in the history
These needed to be more readable and were horribly coded (by me). I
started seeing issues with conversion from bytes on the wire to
variables in spy so I changed how this was done.

Change-Id: I583c43216643b111b6256f39ca475582b37267c6
Reviewed-on: http://review.couchbase.org/9712
Tested-by: Matt Ingenthron <matt@couchbase.com>
Reviewed-by: Matt Ingenthron <matt@couchbase.com>
  • Loading branch information
Mike Wiederhold authored and ingenthr committed Oct 7, 2011
1 parent 48e7e62 commit 591a840
Show file tree
Hide file tree
Showing 7 changed files with 370 additions and 335 deletions.
Expand Up @@ -6,9 +6,9 @@
import net.spy.memcached.ops.OperationCallback;
import net.spy.memcached.ops.TapOperation;
import net.spy.memcached.tapmessage.BaseMessage;
import net.spy.memcached.tapmessage.TapFlag;
import net.spy.memcached.tapmessage.TapOpcode;
import net.spy.memcached.tapmessage.ResponseMessage;
import net.spy.memcached.tapmessage.Util;

public abstract class TapOperationImpl extends OperationImpl implements TapOperation {
private static final byte TAP_FLAG_ACK = 0x1;
Expand Down Expand Up @@ -36,7 +36,7 @@ public void readFromBuffer(ByteBuffer data) throws IOException {
bytesProcessed++;
} else {
if (message == null) {
bodylen = (int) Util.fieldToValue(header, BaseMessage.TOTAL_BODY_INDEX, BaseMessage.TOTAL_BODY_FIELD_LENGTH);
bodylen = decodeInt(header, 8);
message = new byte[BaseMessage.HEADER_LENGTH + bodylen];
System.arraycopy(header, 0, message, 0, BaseMessage.HEADER_LENGTH);
}
Expand All @@ -48,8 +48,10 @@ public void readFromBuffer(ByteBuffer data) throws IOException {
if (bytesProcessed >= message.length) {
ResponseMessage response = new ResponseMessage(message);

if (response.getFlags() == TAP_FLAG_ACK) {
((Callback)getCallback()).gotAck(response.getOpcode(), response.getOpaque());
for (TapFlag flag : response.getFlags()) {
if (flag.flag == TAP_FLAG_ACK) {
((Callback)getCallback()).gotAck(response.getOpcode(), response.getOpaque());
}
}
if (response.getOpcode() != TapOpcode.OPAQUE && response.getOpcode() != TapOpcode.NOOP) {
((Callback)getCallback()).gotData(response);
Expand Down
226 changes: 82 additions & 144 deletions src/main/java/net/spy/memcached/tapmessage/BaseMessage.java
Expand Up @@ -5,263 +5,181 @@
import net.spy.memcached.compat.SpyObject;

/**
* The HeaderMessage implements the header of a tap message. This class cannot be instantiated.
* Tap stream messages are created with the RequestMessage and ResponseMessage classes. Users
* who want to take advantage of customizing their own tap messages should use the
* CustomTapStream class since it provides flexibility to create all valid tap messages.
* The BaseMessage implements the header of a tap message. This class cannot be instantiated.
* Tap stream messages are created with the RequestMessage and ResponseMessage classes.
*/
public class BaseMessage extends SpyObject {
/**
* The index of the magic field in a tap header.
*/
public static final int MAGIC_INDEX = 0;

/**
* The length of the magic field in a tap header.
*/
public static final int MAGIC_FIELD_LENGTH = 1;

/**
* The index of the opcode field in a tap header.
*/
public static final int OPCODE_INDEX = 1;

/**
* The length of the opcode field in a tap header.
*/
public static final int OPCODE_FIELD_LENGTH = 1;

/**
* The index of the key length field in a tap header.
*/
public static final int KEY_LENGTH_INDEX = 2;

/**
* The length of the key length field in a tap header.
*/
public static final int KEY_LENGTH_FIELD_LENGTH = 2;

/**
* The index of the extra length field in the tap header.
*/
public static final int EXTRA_LENGTH_INDEX = 4;

/**
* The length of the extra length field in a tap header.
*/
public static final int EXTRA_LENGTH_FIELD_LENGTH = 1;

/**
* The index of the data type field in the tap header.
*/
public static final int DATA_TYPE_INDEX = 5;

/**
* The length of the data type field in a tap header.
*/
public static final int DATA_TYPE_FIELD_LENGTH = 1;

/**
* The index of the vbucket field in the tap header.
*/
public static final int VBUCKET_INDEX = 6;

/**
* The length of the vbucket field in a tap header.
*/
public static final int VBUCKET_FIELD_LENGTH = 2;

/**
* The index of the total body field in the tap header.
*/
public static final int TOTAL_BODY_INDEX = 8;

/**
* The length of the total body field in the tap header.
*/
public static final int TOTAL_BODY_FIELD_LENGTH = 4;

/**
* The index of the opaque field in the tap header.
*/
public static final int OPAQUE_INDEX = 12;

/**
* The length of the opaque field in the tap header.
*/
public static final int OPAQUE_FIELD_LENGTH = 4;

/**
* The index of the cas field in the tap header.
*/
public static final int CAS_INDEX = 16;

/**
* The length of the cas field in the tap header.
*/
public static final int CAS_FIELD_LENGTH = 8;

/**
* The header length
*/
public abstract class BaseMessage extends SpyObject {
private static final int MAGIC_OFFSET = 0;
private static final int OPCODE_OFFSET = 1;
private static final int KEYLENGTH_OFFSET = 2;
private static final int EXTRALENGTH_OFFSET = 4;
private static final int DATATYPE_OFFSET = 5;
private static final int VBUCKET_OFFSET = 6;
private static final int TOTALBODY_OFFSET = 8;
private static final int OPAQUE_OFFSET = 12;
private static final int CAS_OFFSET = 16;
public static final int HEADER_LENGTH = 24;

/**
* Holds the binary data for the header field.
*/
protected TapMagic magic;
protected TapOpcode opcode;
protected short keylength;
protected byte extralength;
protected byte datatype;
protected short vbucket;
protected int totalbody;
protected int opaque;
protected long cas;

protected byte[] mbytes;
/**
* Instantiates a tap header.
*/
protected BaseMessage() {
mbytes = new byte[HEADER_LENGTH];
// Empty
}

protected BaseMessage(byte[] b) {
magic = TapMagic.getMagicByByte(b[MAGIC_OFFSET]);
opcode = TapOpcode.getOpcodeByByte(b[OPCODE_OFFSET]);
keylength = decodeShort(b, KEYLENGTH_OFFSET);
extralength = b[EXTRALENGTH_OFFSET];
datatype = b[DATATYPE_OFFSET];
vbucket = decodeShort(b, VBUCKET_OFFSET);
totalbody = decodeInt(b, TOTALBODY_OFFSET);
opaque = decodeInt(b, OPAQUE_OFFSET);
cas = decodeLong(b, CAS_OFFSET);
}

/**
* Sets the value of the tap messages magic field.
* @param m The new value for the magic field.
*/
public final void setMagic(TapMagic m) {
mbytes[MAGIC_INDEX] = (byte) m.magic;
magic = m;
}

/**
* Gets the value of the tap messages magic field.
* @return The value of the magic field.
*/
public final int getMagic() {
return mbytes[MAGIC_INDEX];
public final TapMagic getMagic() {
return magic;
}

/**
* Sets the value of the tap messages opcode field
* @param o The new value of the opcode field.
*/
public final void setOpcode(TapOpcode o) {
mbytes[OPCODE_INDEX] = (byte) o.opcode;
opcode = o;
}

/**
* Gets the value of the tap messages opaque field.
* @return The value of the opaque field.
*/
public final TapOpcode getOpcode() {
return TapOpcode.getOpcodeByByte(mbytes[OPCODE_INDEX]);
}

/**
* Sets the key length for this message. This function should never be called by
* the user since changes to fields that affect key length call this function
* automatically.
* @param l The new value for the key length field.
*/
protected final void setKeylength(long l) {
Util.valueToFieldOffest(mbytes, KEY_LENGTH_INDEX, KEY_LENGTH_FIELD_LENGTH, l);
return opcode;
}

/**
* Gets the value of the tap messages key length field.
* @return The value of the key length field.
*/
public final int getKeylength() {
return (int) Util.fieldToValue(mbytes, KEY_LENGTH_INDEX, KEY_LENGTH_FIELD_LENGTH);
public final short getKeylength() {
return keylength;
}

/**
* Sets the value of the tap messages data type field.
* @param b The new value for the data type field.
*/
public final void setDatatype(byte b) {
mbytes[DATA_TYPE_INDEX] = b;
public final void setDatatype(byte d) {
datatype = d;
}

/**
* Gets the value of the tap messages data type field.
* @return The value of the data type field.
*/
public final byte getDatatype() {
return mbytes[DATA_TYPE_INDEX];
return datatype;
}

/**
* Sets the value of the tap messages extra length field.
* @param i The new value for the extra length field.
*/
public final void setExtralength(int i) {
mbytes[EXTRA_LENGTH_INDEX] = (byte) i;
public final void setExtralength(byte e) {
extralength = e;
}

/**
* Gets the value of the tap messages extra length field.
* @return The value of the extra length field.
*/
public final int getExtralength() {
return mbytes[EXTRA_LENGTH_INDEX];
public final byte getExtralength() {
return extralength;
}

/**
* Sets the value of the tap messages vbucket field.
* @param vb The new value for the vbucket field.
*/
public final void setVbucket(int vb) {
Util.valueToFieldOffest(mbytes, VBUCKET_INDEX, VBUCKET_FIELD_LENGTH, vb);
public final void setVbucket(short vb) {
vbucket = vb;
}

/**
* Gets the value of the tap messages vbucket field.
* @return The value of the vbucket field.
*/
public final int getVbucket() {
return (int) Util.fieldToValue(mbytes, VBUCKET_INDEX, VBUCKET_FIELD_LENGTH);
public final short getVbucket() {
return vbucket;
}

/**
* Sets the value of the tap messages total body field.
* @param l The new value for the total body field.
*/
public final void setTotalbody(long l) {
Util.valueToFieldOffest(mbytes, TOTAL_BODY_INDEX, TOTAL_BODY_FIELD_LENGTH, l);
public final void setTotalbody(int t) {
totalbody = t;
}

/**
* Gets the value of the tap messages total body field.
* @return The value of the total body field.
*/
public final int getTotalbody() {
return (int) Util.fieldToValue(mbytes, TOTAL_BODY_INDEX, TOTAL_BODY_FIELD_LENGTH);
return totalbody;
}

/**
* Sets the value of the tap messages opaque field.
* @param op The new value for the opaque field.
*/
public final void setOpaque(int op) {
Util.valueToFieldOffest(mbytes, OPAQUE_INDEX, OPAQUE_FIELD_LENGTH, op);
opaque = op;
}

/**
* Gets the value of the tap messages opaque field.
* @return The value of the opaque field.
*/
public final int getOpaque() {
return (int) Util.fieldToValue(mbytes, OPAQUE_INDEX, OPAQUE_FIELD_LENGTH);
return opaque;
}

/**
* Sets the value of the tap messages cas field.
* @param cas The new value for the cas field.
*/
public final void setCas(long cas) {
Util.valueToFieldOffest(mbytes, CAS_INDEX, CAS_FIELD_LENGTH, cas);
public final void setCas(long c) {
cas = c;
}

/**
* Gets the value of the tap messages cas field.
* @return The value of the cas field.
*/
public final long getCas() {
return Util.fieldToValue(mbytes, CAS_INDEX, CAS_FIELD_LENGTH);
return cas;
}

/**
Expand All @@ -276,7 +194,27 @@ public final int getMessageLength() {
* Creates a ByteBuffer representation of the message.
* @return The ByteBuffer representation of the message.
*/
public final ByteBuffer getBytes() {
return ByteBuffer.wrap(mbytes);
public abstract ByteBuffer getBytes();

protected short decodeShort(byte[] data, int i) {
return (short)((data[i] & 0xff) << 8 | (data[i + 1] & 0xff));
}

protected int decodeInt(byte[] data, int i) {
return (data[i] & 0xff) << 24
| (data[i + 1] & 0xff) << 16
| (data[i + 2] & 0xff) << 8
| (data[i + 3] & 0xff);
}

protected long decodeLong(byte[] data, int i) {
return (data[i] & 0xffL) << 56
| (data[i + 1] & 0xffL) << 48
| (data[i + 2] & 0xffL) << 40
| (data[i + 3] & 0xffL) << 32
| (data[i + 4] & 0xffL) << 24
| (data[i + 5] & 0xffL) << 16
| (data[i + 6] & 0xffL) << 8
| (data[i + 7] & 0xffL);
}
}

0 comments on commit 591a840

Please sign in to comment.