package org.corfudb.protocols.logprotocol; import io.netty.buffer.ByteBuf; import lombok.*; import org.corfudb.runtime.CorfuRuntime; import org.corfudb.util.serializer.ISerializer; import org.corfudb.util.serializer.Serializers; import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.UUID; /** * Created by mwei on 1/8/16. */ @ToString(callSuper = true) @NoArgsConstructor public class SMREntry extends LogEntry implements ISMRConsumable { /** * The name of the SMR method. Note that this is limited to the size of a short. */ @Getter private String SMRMethod; /** * The arguments to the SMR method, which could be 0. */ @Getter private Object[] SMRArguments; /** * The serializer used to serialize the SMR arguments. */ @Getter private ISerializer serializerType; /** An undo record, which can be used to undo this method. * */ @Getter public transient Object undoRecord; /** A flag indicating whether an undo record is present. Necessary * because undo records may be NULL. */ @Getter public boolean undoable; /** The upcall result, if present. */ @Getter public transient Object upcallResult; /** If there is an upcall result for this modification. */ @Getter public transient boolean haveUpcallResult = false; /** Set the upcall result for this entry. */ public void setUpcallResult(Object result) { upcallResult = result; haveUpcallResult = true; } /** Set the undo record for this entry. */ public void setUndoRecord(Object object) { this.undoRecord = object; undoable = true; } /** Clear the undo record for this entry. */ public void clearUndoRecord() { this.undoRecord = null; undoable = false; } public SMREntry(String SMRMethod, @NonNull Object[] SMRArguments, ISerializer serializer) { super(LogEntryType.SMR); this.SMRMethod = SMRMethod; this.SMRArguments = SMRArguments; this.serializerType = serializer; } /** * This function provides the remaining buffer. Child entries * should initialize their contents based on the buffer. * * @param b The remaining buffer. */ @Override void deserializeBuffer(ByteBuf b, CorfuRuntime rt) { super.deserializeBuffer(b, rt); short methodLength = b.readShort(); byte[] methodBytes = new byte[methodLength]; b.readBytes(methodBytes, 0, methodLength); SMRMethod = new String(methodBytes); serializerType = Serializers.getSerializer(b.readByte()); byte numArguments = b.readByte(); Object[] arguments = new Object[numArguments]; for (byte arg = 0; arg < numArguments; arg++) { int len = b.readInt(); ByteBuf objBuf = b.slice(b.readerIndex(), len); arguments[arg] = serializerType.deserialize(objBuf, rt); b.skipBytes(len); } SMRArguments = arguments; } @Override public void serialize(ByteBuf b) { super.serialize(b); b.writeShort(SMRMethod.length()); b.writeBytes(SMRMethod.getBytes()); b.writeByte(serializerType.getType()); b.writeByte(SMRArguments.length); Arrays.stream(SMRArguments) .forEach(x -> { int lengthIndex = b.writerIndex(); b.writeInt(0); serializerType.serialize(x, b); int length = b.writerIndex() - lengthIndex - 4; b.writerIndex(lengthIndex); b.writeInt(length); b.writerIndex(lengthIndex + length + 4); }); } @Override public List<SMREntry> getSMRUpdates(UUID id) { // TODO: we should check that the id matches the id of this entry, // but replex erases this information. return Collections.singletonList(this); } }