package org.corfudb.protocols.wireprotocol; import io.netty.buffer.ByteBuf; import lombok.AllArgsConstructor; import lombok.Data; import java.util.Set; import java.util.UUID; /** * A token request is at the heart of the Corfu log protocol. * * There are four token request scenarios, designated by the relevant constants : * 0. {@link TokenRequest::TK_QUERY} : Query of the current log tail and of specific stream-tails. * 1. {@link TokenRequest::TK_RAW} : Ask for raw (global) log token(s). * This extends the global log tail by the requested # of tokens. * 2. {@link TokenRequest::TK_STREAM} : Ask for token(s) on a specific stream. * This extends both the global log tail, and the specific stream tail, by the requested # of tokens. * 3. {@link TokenRequest::TK_MULTI_STREAM} : Ask for token(s) on multiple streams. * This extends both the global log tail, and each of the specified stream tails, by the requested # of tokens. * 4. {@link TokenRequest::TK_TX} : * First, check transaction resolution. If transaction can commit, then behave like {@link TokenRequest::TK_MULTI_STREAM}. */ @Data @AllArgsConstructor public class TokenRequest implements ICorfuPayload<TokenRequest> { public static final byte TK_QUERY = 0; public static final byte TK_RAW = 1; // todo: remove ..public static final byte TK_STREAM = 2; public static final byte TK_MULTI_STREAM = 3; public static final byte TK_TX = 4; /** The type of request, one of the above */ final byte reqType; /** The number of tokens to request. */ final Long numTokens; /** The streams which are written to by this token request. */ final Set<UUID> streams; /* used for transaction resolution. */ final TxResolutionInfo txnResolution; public TokenRequest(Long numTokens, Set<UUID> streams, TxResolutionInfo conflictInfo) { reqType = TK_TX; this.numTokens = numTokens; this.streams = streams; txnResolution = conflictInfo; } public TokenRequest(Long numTokens, Set<UUID> streams) { if (numTokens == 0) this.reqType = TK_QUERY; else if (streams == null || streams.size() == 0) this.reqType = TK_RAW; else this.reqType = TK_MULTI_STREAM; this.numTokens = numTokens; this.streams = streams; txnResolution = null; } public TokenRequest(ByteBuf buf) { reqType = ICorfuPayload.fromBuffer(buf, Byte.class); switch (reqType) { case TK_QUERY: numTokens = 0L; streams = ICorfuPayload.setFromBuffer(buf, UUID.class); txnResolution = null; break; case TK_RAW: numTokens = ICorfuPayload.fromBuffer(buf, Long.class); streams = null; txnResolution = null; break; case TK_MULTI_STREAM: numTokens = ICorfuPayload.fromBuffer(buf, Long.class); streams = ICorfuPayload.setFromBuffer(buf, UUID.class); txnResolution = null; break; case TK_TX: numTokens = ICorfuPayload.fromBuffer(buf, Long.class); streams = ICorfuPayload.setFromBuffer(buf, UUID.class); txnResolution = new TxResolutionInfo(buf); break; default: numTokens = -1L; streams = null; txnResolution = null; break; } } @Override public void doSerialize(ByteBuf buf) { ICorfuPayload.serialize(buf, reqType); if (reqType != TK_QUERY) ICorfuPayload.serialize(buf, numTokens); if (reqType != TK_RAW) ICorfuPayload.serialize(buf, streams); if (reqType == TK_TX) ICorfuPayload.serialize(buf, txnResolution); } }