package org.corfudb.protocols.wireprotocol; import com.google.common.reflect.TypeToken; import lombok.AllArgsConstructor; import lombok.Getter; import lombok.RequiredArgsConstructor; import org.corfudb.runtime.view.Layout; import java.lang.invoke.LambdaMetafactory; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; import java.lang.reflect.Constructor; /** * Created by mwei on 8/8/16. */ @RequiredArgsConstructor @AllArgsConstructor public enum CorfuMsgType { // Base Messages PING(0, TypeToken.of(CorfuMsg.class)), PONG(1, TypeToken.of(CorfuMsg.class), true), RESET(2, TypeToken.of(CorfuMsg.class), true), SET_EPOCH(3, new TypeToken<CorfuPayloadMsg<Long>>() {}, true), ACK(4, TypeToken.of(CorfuMsg.class), true), WRONG_EPOCH(5, new TypeToken<CorfuPayloadMsg<Long>>() {}, true), NACK(6, TypeToken.of(CorfuMsg.class)), VERSION_REQUEST(7, TypeToken.of(CorfuMsg.class), true), VERSION_RESPONSE(8, new TypeToken<JSONPayloadMsg<VersionInfo>>() {}, true), // Layout Messages LAYOUT_REQUEST(10, new TypeToken<CorfuPayloadMsg<Long>>(){}, true), LAYOUT_RESPONSE(11, TypeToken.of(LayoutMsg.class), true), LAYOUT_PREPARE(12, new TypeToken<CorfuPayloadMsg<LayoutPrepareRequest>>(){}, true), LAYOUT_PREPARE_REJECT(13, new TypeToken<CorfuPayloadMsg<LayoutPrepareResponse>>(){}), LAYOUT_PROPOSE(14, new TypeToken<CorfuPayloadMsg<LayoutProposeRequest>>(){}, true), LAYOUT_PROPOSE_REJECT(15, new TypeToken<CorfuPayloadMsg<LayoutProposeResponse>>(){}), LAYOUT_COMMITTED(16, new TypeToken<CorfuPayloadMsg<LayoutCommittedRequest>>(){}, true), LAYOUT_QUERY(17, new TypeToken<CorfuPayloadMsg<Long>>(){}), LAYOUT_BOOTSTRAP(18, new TypeToken<CorfuPayloadMsg<LayoutBootstrapRequest>>(){}, true), LAYOUT_NOBOOTSTRAP(19, TypeToken.of(CorfuMsg.class), true), // Sequencer Messages TOKEN_REQ(20, new TypeToken<CorfuPayloadMsg<TokenRequest>>(){}), TOKEN_RES(21, new TypeToken<CorfuPayloadMsg<TokenResponse>>(){}), RESET_SEQUENCER(22, new TypeToken<CorfuPayloadMsg<Long>>(){}), // Logging Unit Messages WRITE(30, new TypeToken<CorfuPayloadMsg<WriteRequest>>() {}), READ_REQUEST(31, new TypeToken<CorfuPayloadMsg<ReadRequest>>() {}), READ_RESPONSE(32, new TypeToken<CorfuPayloadMsg<ReadResponse>>() {}), TRIM(33, new TypeToken<CorfuPayloadMsg<TrimRequest>>() {}), FILL_HOLE(34, new TypeToken<CorfuPayloadMsg<TrimRequest>>() {}), FORCE_GC(35, TypeToken.of(CorfuMsg.class)), GC_INTERVAL(36, new TypeToken<CorfuPayloadMsg<Long>>() {}), FORCE_COMPACT(37, TypeToken.of(CorfuMsg.class)), COMMIT(40, new TypeToken<CorfuPayloadMsg<CommitRequest>>() {}), TAIL_REQUEST(41, TypeToken.of(CorfuMsg.class), true), TAIL_RESPONSE(42, new TypeToken<CorfuPayloadMsg<Long>>(){}, true), WRITE_OK(50, TypeToken.of(CorfuMsg.class)), ERROR_TRIMMED(51, TypeToken.of(CorfuMsg.class)), ERROR_OVERWRITE(52, TypeToken.of(CorfuMsg.class)), ERROR_OOS(53, TypeToken.of(CorfuMsg.class)), ERROR_RANK(54, TypeToken.of(CorfuMsg.class)), ERROR_NOENTRY(55, TypeToken.of(CorfuMsg.class)), ERROR_REPLEX_OVERWRITE(56, TypeToken.of(CorfuMsg.class)), ERROR_DATA_CORRUPTION(57, new TypeToken<CorfuPayloadMsg<ReadResponse>>() {}), ERROR_DATA_OUTRANKED(58, TypeToken.of(CorfuMsg.class)), ERROR_VALUE_ADOPTED(59,new TypeToken<CorfuPayloadMsg<ReadResponse>>() {}), // EXTRA CODES LAYOUT_ALREADY_BOOTSTRAP(60, TypeToken.of(CorfuMsg.class), true), LAYOUT_PREPARE_ACK(61, new TypeToken<CorfuPayloadMsg<LayoutPrepareResponse>>(){}, true), // Management Messages MANAGEMENT_BOOTSTRAP_REQUEST(70, new TypeToken<CorfuPayloadMsg<Layout>>(){}, true), MANAGEMENT_NOBOOTSTRAP_ERROR(71, TypeToken.of(CorfuMsg.class), true), MANAGEMENT_ALREADY_BOOTSTRAP_ERROR(72, TypeToken.of(CorfuMsg.class), true), MANAGEMENT_START_FAILURE_HANDLER(73, TypeToken.of(CorfuMsg.class), true), MANAGEMENT_FAILURE_DETECTED(74, new TypeToken<CorfuPayloadMsg<FailureDetectorMsg>>(){}, true), HEARTBEAT_REQUEST(75, TypeToken.of(CorfuMsg.class), true), HEARTBEAT_RESPONSE(76, new TypeToken<CorfuPayloadMsg<byte[]>>(){}, true); public final int type; public final TypeToken<? extends CorfuMsg> messageType; //public final Class<? extends AbstractServer> handler; public Boolean ignoreEpoch = false; public <T> CorfuPayloadMsg<T> payloadMsg(T payload) { // todo:: maybe some typechecking here (performance impact?) return new CorfuPayloadMsg<T>(this, payload); } public CorfuMsg msg() { return new CorfuMsg(this); } @FunctionalInterface interface MessageConstructor<T> { T construct(); } @Getter(lazy=true) private final MessageConstructor<? extends CorfuMsg> constructor = resolveConstructor(); public byte asByte() { return (byte) type; } /** A lookup representing the context we'll use to do lookups. */ private static java.lang.invoke.MethodHandles.Lookup lookup = MethodHandles.lookup(); /** Generate a lambda pointing to the constructor for this message type. */ @SuppressWarnings("unchecked") private MessageConstructor<? extends CorfuMsg> resolveConstructor() { // Grab the constructor and get convert it to a lambda. try { Constructor t = messageType.getRawType().getConstructor(); MethodHandle mh = lookup.unreflectConstructor(t); MethodType mt = MethodType.methodType(Object.class); try { return (MessageConstructor<? extends CorfuMsg>) LambdaMetafactory.metafactory(lookup, "construct", MethodType.methodType(MessageConstructor.class), mt, mh, mh.type()) .getTarget().invokeExact(); } catch (Throwable th) { throw new RuntimeException(th); } } catch (NoSuchMethodException nsme) { throw new RuntimeException("CorfuMsgs must include a no-arg constructor!"); } catch (IllegalAccessException e) { throw new RuntimeException(e); } } }