All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.dizitart.no2.collection.SnowflakeIdGenerator Maven / Gradle / Ivy

/*
 * Copyright (c) 2017-2020. Nitrite author or authors.
 *
 * 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 org.dizitart.no2.collection;


import lombok.extern.slf4j.Slf4j;

import java.nio.ByteBuffer;
import java.security.SecureRandom;
import java.util.UUID;

/**
 * Generate unique IDs using the Twitter Snowflake algorithm (see Snowflake).
 * Snowflake IDs are 64 bit positive longs composed of:
 *
 * 
    *
  • 41 bits time stamp
  • *
  • 10 bits machine id
  • *
  • 12 bits sequence number
  • *
  • 1 unused sign bit, always set to 0
  • *
*

* This is a derivative work of - * Sebastian Schaffert *

* * @author Sebastian Schaffert ([email protected]) * @since 4.0 */ @Slf4j(topic = "nitrite") public class SnowflakeIdGenerator { private final SecureRandom random; private final long nodeIdBits = 10L; private long nodeId; private volatile long lastTimestamp = -1L; private volatile long sequence = 0L; private static final long no2epoch = 1288834974657L; public SnowflakeIdGenerator() { random = new SecureRandom(); long maxNodeId = ~(-1L << nodeIdBits); this.nodeId = getNodeId(); if (this.nodeId > maxNodeId) { log.warn("nodeId > maxNodeId; using random node id"); this.nodeId = random.nextInt((int) maxNodeId) + 1; } log.debug("initialised with node id {}", this.nodeId); } protected long tillNextMillis(long lastTimestamp) { long timestamp = System.currentTimeMillis(); while (timestamp <= lastTimestamp) { timestamp = System.currentTimeMillis(); } return timestamp; } protected long getNodeId() { byte[] uuid = asBytes(UUID.randomUUID()); byte rndByte = (byte) (random.nextInt() & 0x000000FF); return ((0x000000FF & (long) uuid[uuid.length - 1]) | (0x0000FF00 & (((long) rndByte) << 8))) >> 6; } /** * Return the next unique id for the type with the given name using the generator's id generation strategy. * * @return next unique id */ public synchronized long getId() { long timestamp = System.currentTimeMillis(); if (timestamp < lastTimestamp) { log.warn("Clock moved backwards. Refusing to generate id for {} milliseconds.", (lastTimestamp - timestamp)); try { Thread.sleep((lastTimestamp - timestamp)); } catch (InterruptedException ignore) { } } long sequenceBits = 12L; if (lastTimestamp == timestamp) { long sequenceMask = ~(-1L << sequenceBits); sequence = (sequence + 1) & sequenceMask; if (sequence == 0) { timestamp = tillNextMillis(lastTimestamp); } } else { sequence = 0; } lastTimestamp = timestamp; long timestampLeftShift = sequenceBits + nodeIdBits; long id = ((timestamp - no2epoch) << timestampLeftShift) | (nodeId << sequenceBits) | sequence; if (id < 0) { log.warn("Generated id is negative: {}", id); } return id; } private byte[] asBytes(UUID uuid) { ByteBuffer bb = ByteBuffer.wrap(new byte[16]); bb.putLong(uuid.getMostSignificantBits()); bb.putLong(uuid.getLeastSignificantBits()); return bb.array(); } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy