package org.corfudb.protocols.wireprotocol; import com.esotericsoftware.kryo.NotNull; import com.google.common.reflect.TypeToken; import lombok.AllArgsConstructor; import lombok.Getter; import lombok.RequiredArgsConstructor; import lombok.Value; import javax.annotation.Nullable; import java.util.Arrays; import java.util.Collections; import java.util.EnumMap; import java.util.Map; import java.util.Optional; import java.util.Set; import java.util.UUID; import java.util.function.Function; import java.util.stream.Collectors; /** * Created by mwei on 9/18/15. */ public interface IMetadata { Map<Byte, LogUnitMetadataType> metadataTypeMap = Arrays.<LogUnitMetadataType>stream(LogUnitMetadataType.values()) .collect(Collectors.toMap(LogUnitMetadataType::asByte, Function.identity())); EnumMap<IMetadata.LogUnitMetadataType, Object> getMetadataMap(); /** * Get the streams that belong to this append. * * @return A set of streams that belong to this append. */ @SuppressWarnings("unchecked") default Set<UUID> getStreams() { return (Set<UUID>) ((Map<UUID, Long>)getMetadataMap().getOrDefault( LogUnitMetadataType.BACKPOINTER_MAP, Collections.emptyMap())).keySet(); } /** * Get whether or not this entry contains a given stream. * @param stream The stream to check. * @return True, if the entry contains the given stream. */ default boolean containsStream(UUID stream) { return getBackpointerMap().keySet().contains(stream); } /** * Get the rank of this append. * * @return The rank of this append. */ @SuppressWarnings("unchecked") @Nullable default DataRank getRank() { return (DataRank) getMetadataMap().getOrDefault(LogUnitMetadataType.RANK, null); } /** * Set the rank of this append. * * @param rank The rank of this append. */ default void setRank(@Nullable DataRank rank) { EnumMap<LogUnitMetadataType, Object> map = getMetadataMap(); if (rank != null) { map.put(LogUnitMetadataType.RANK, rank); } else { if (map.containsKey(LogUnitMetadataType.RANK)) { map.remove(LogUnitMetadataType.RANK); } } } @SuppressWarnings("unchecked") default Map<UUID, Long> getBackpointerMap() { return (Map<UUID, Long>) getMetadataMap().getOrDefault(LogUnitMetadataType.BACKPOINTER_MAP, Collections.EMPTY_MAP); } default void setBackpointerMap(Map<UUID, Long> backpointerMap) { getMetadataMap().put(LogUnitMetadataType.BACKPOINTER_MAP, backpointerMap); } default void setGlobalAddress(Long address) { getMetadataMap().put(LogUnitMetadataType.GLOBAL_ADDRESS, address); } @SuppressWarnings("unchecked") default Long getGlobalAddress() { if (getMetadataMap() == null || getMetadataMap().get(LogUnitMetadataType.GLOBAL_ADDRESS) == null) { return -1L; } return Optional.ofNullable((Long) getMetadataMap().get(LogUnitMetadataType.GLOBAL_ADDRESS)).orElse((long) -1); } default void clearCommit() { getMetadataMap().put(LogUnitMetadataType.COMMIT, false); } default void setCommit() { getMetadataMap().put(LogUnitMetadataType.COMMIT, true); } @RequiredArgsConstructor public enum LogUnitMetadataType implements ITypedEnum { RANK(1, TypeToken.of(DataRank.class)), BACKPOINTER_MAP(3, new TypeToken<Map<UUID, Long>>() {}), GLOBAL_ADDRESS(4, TypeToken.of(Long.class)), COMMIT(5, TypeToken.of(Boolean.class)) ; final int type; @Getter final TypeToken<?> componentType; public byte asByte() { return (byte) type; } public static Map<Byte, LogUnitMetadataType> typeMap = Arrays.<LogUnitMetadataType>stream(LogUnitMetadataType.values()) .collect(Collectors.toMap(LogUnitMetadataType::asByte, Function.identity())); } @Value @AllArgsConstructor class DataRank implements Comparable<DataRank> { public long rank; @NotNull public UUID uuid; public DataRank(long rank) { this(rank, UUID.randomUUID()); } public DataRank buildHigherRank() { return new DataRank(rank+1, uuid); } @Override public int compareTo(DataRank o) { int rankCompared = Long.compare(this.rank, o.rank); if (rankCompared==0) { return uuid.compareTo(o.getUuid()); } else { return rankCompared; } } } }