/* * Copyright (c) 2015-2017, Christoph Engelbert (aka noctarius) and * contributors. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.noctarius.snowcast.impl; import com.hazelcast.instance.BuildInfo; import com.hazelcast.instance.BuildInfoProvider; import com.hazelcast.util.QuickMath; import com.noctarius.snowcast.SnowcastMaxLogicalNodeIdOutOfBoundsException; import com.noctarius.snowcast.SnowcastSequenceComparator; import com.noctarius.snowcast.SnowcastSequencer; import javax.annotation.Nonnegative; import javax.annotation.Nonnull; import javax.validation.constraints.Max; import javax.validation.constraints.Min; import java.util.Comparator; import static com.noctarius.snowcast.impl.ExceptionMessages.ILLEGAL_MAX_LOGICAL_NODE_COUNT; import static com.noctarius.snowcast.impl.ExceptionMessages.ILLEGAL_MAX_LOGICAL_NODE_ID_BOUNDARY; import static com.noctarius.snowcast.impl.ExceptionMessages.NEXT_ID_LARGER_THAN_ALLOWED_MAX_COUNTER; import static com.noctarius.snowcast.impl.ExceptionUtils.exception; import static com.noctarius.snowcast.impl.SnowcastConstants.ID_TIMESTAMP_READ_MASK; import static com.noctarius.snowcast.impl.SnowcastConstants.MAX_LOGICAL_NODE_COUNT_1024; import static com.noctarius.snowcast.impl.SnowcastConstants.MAX_LOGICAL_NODE_COUNT_128; import static com.noctarius.snowcast.impl.SnowcastConstants.MAX_LOGICAL_NODE_COUNT_2048; import static com.noctarius.snowcast.impl.SnowcastConstants.MAX_LOGICAL_NODE_COUNT_256; import static com.noctarius.snowcast.impl.SnowcastConstants.MAX_LOGICAL_NODE_COUNT_4096; import static com.noctarius.snowcast.impl.SnowcastConstants.MAX_LOGICAL_NODE_COUNT_512; import static com.noctarius.snowcast.impl.SnowcastConstants.MAX_LOGICAL_NODE_COUNT_8192; import static com.noctarius.snowcast.impl.SnowcastConstants.NODE_ID_LOWER_BOUND; import static com.noctarius.snowcast.impl.SnowcastConstants.NODE_ID_UPPER_BOUND; import static com.noctarius.snowcast.impl.SnowcastConstants.SHIFT_LOGICAL_NODE_ID_1024; import static com.noctarius.snowcast.impl.SnowcastConstants.SHIFT_LOGICAL_NODE_ID_128; import static com.noctarius.snowcast.impl.SnowcastConstants.SHIFT_LOGICAL_NODE_ID_2048; import static com.noctarius.snowcast.impl.SnowcastConstants.SHIFT_LOGICAL_NODE_ID_256; import static com.noctarius.snowcast.impl.SnowcastConstants.SHIFT_LOGICAL_NODE_ID_4096; import static com.noctarius.snowcast.impl.SnowcastConstants.SHIFT_LOGICAL_NODE_ID_512; import static com.noctarius.snowcast.impl.SnowcastConstants.SHIFT_LOGICAL_NODE_ID_8192; import static com.noctarius.snowcast.impl.SnowcastConstants.SHIFT_TIMESTAMP; public final class InternalSequencerUtils { private InternalSequencerUtils() { } @Nonnull public static Comparator<Long> snowcastSequenceComparator(@Nonnull SnowcastSequencer sequencer) { SequencerDefinition definition = ((InternalSequencer) sequencer).getSequencerDefinition(); return new SnowcastSequenceComparator(definition.getMaxLogicalNodeCount()); } @Nonnegative public static int calculateBoundedMaxLogicalNodeCount(int maxLogicalNodeCount) { if (maxLogicalNodeCount < NODE_ID_LOWER_BOUND) { throw exception(SnowcastMaxLogicalNodeIdOutOfBoundsException::new, // ILLEGAL_MAX_LOGICAL_NODE_ID_BOUNDARY, "smaller", NODE_ID_LOWER_BOUND); } if (maxLogicalNodeCount > NODE_ID_UPPER_BOUND) { throw exception(SnowcastMaxLogicalNodeIdOutOfBoundsException::new, // ILLEGAL_MAX_LOGICAL_NODE_ID_BOUNDARY, "larger", NODE_ID_UPPER_BOUND); } return QuickMath.nextPowerOfTwo(maxLogicalNodeCount) - 1; } @Nonnegative public static int calculateMaxMillisCounter(@Nonnegative int shiftLogicalNodeId) { return (int) Math.pow(2, shiftLogicalNodeId); } @Nonnegative public static int calculateLogicalNodeShifting(@Min(128) @Max(8192) int maxLogicalNodeCount) { switch (maxLogicalNodeCount) { case MAX_LOGICAL_NODE_COUNT_128: return SHIFT_LOGICAL_NODE_ID_128; case MAX_LOGICAL_NODE_COUNT_256: return SHIFT_LOGICAL_NODE_ID_256; case MAX_LOGICAL_NODE_COUNT_512: return SHIFT_LOGICAL_NODE_ID_512; case MAX_LOGICAL_NODE_COUNT_1024: return SHIFT_LOGICAL_NODE_ID_1024; case MAX_LOGICAL_NODE_COUNT_2048: return SHIFT_LOGICAL_NODE_ID_2048; case MAX_LOGICAL_NODE_COUNT_4096: return SHIFT_LOGICAL_NODE_ID_4096; case MAX_LOGICAL_NODE_COUNT_8192: return SHIFT_LOGICAL_NODE_ID_8192; default: throw exception(IllegalArgumentException::new, ILLEGAL_MAX_LOGICAL_NODE_COUNT); } } @Nonnegative public static long calculateLogicalNodeMask(@Min(128) @Max(8192) long maxLogicalNodeCount, @Nonnegative int nodeIdShiftFactor) { return (maxLogicalNodeCount) << nodeIdShiftFactor; } public static long calculateCounterMask(@Min(128) @Max(8192) long maxLogicalNodeCount, @Nonnegative int nodeIdShiftFactor) { long logicalNodeMask = maxLogicalNodeCount << nodeIdShiftFactor; long invMask = ID_TIMESTAMP_READ_MASK | logicalNodeMask; return ~invMask; } public static long generateSequenceId(@Nonnegative long timestamp, @Min(128) @Max(8192) int logicalNodeID, @Nonnegative int nextId, @Nonnegative int nodeIdShiftFactor) { int maxCounter = calculateMaxMillisCounter(nodeIdShiftFactor); if (maxCounter < nextId) { throw exception(NEXT_ID_LARGER_THAN_ALLOWED_MAX_COUNTER); } long id = timestamp << SHIFT_TIMESTAMP; id |= logicalNodeID << nodeIdShiftFactor; id |= nextId; return id; } @Nonnegative public static long timestampValue(long sequenceId) { return (sequenceId & ID_TIMESTAMP_READ_MASK) >>> SHIFT_TIMESTAMP; } @Nonnegative public static int logicalNodeId(long sequenceId, @Nonnegative int nodeIdShiftFactor, long mask) { return (int) ((sequenceId & mask) >>> nodeIdShiftFactor); } @Nonnegative public static int counterValue(long sequenceId, long mask) { return (int) (sequenceId & mask); } static void printStartupMessage(boolean client) { StringBuilder sb = new StringBuilder(); if (!SnowcastConstants.LOGO_DISABLED) { sb.append(SnowcastConstants.SNOWCAST_ASCII_LOGO).append('\n'); } sb.append("snowcast ").append(client ? "client" : "member").append(" mode - "); sb.append(" version: ").append(SnowcastConstants.VERSION).append(" "); sb.append("build-date: ").append(SnowcastConstants.BUILD_DATE).append('\n'); System.out.println(sb.toString()); } static SnowcastConstants.HazelcastVersion getHazelcastVersion() { BuildInfo buildInfo = BuildInfoProvider.getBuildInfo(); if (buildInfo.getVersion() == null) { return SnowcastConstants.HazelcastVersion.Unknown; } if (buildInfo.getVersion().startsWith("3.7")) { return SnowcastConstants.HazelcastVersion.V_3_7; } else if (buildInfo.getVersion().startsWith("3.8")) { return SnowcastConstants.HazelcastVersion.V_3_8; } return SnowcastConstants.HazelcastVersion.Unknown; } }