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

rpc.turbo.util.uuid.ObjectId Maven / Gradle / Ivy

There is a newer version: 0.0.9
Show newest version
package rpc.turbo.util.uuid;

import static java.time.ZoneOffset.UTC;
import static rpc.turbo.util.HexUtils.byteToHexLE;
import static rpc.turbo.util.UnsafeUtils.unsafe;
import static sun.misc.Unsafe.ARRAY_BYTE_BASE_OFFSET;

import java.io.Serializable;
import java.net.NetworkInterface;
import java.nio.BufferUnderflowException;
import java.nio.ByteBuffer;
import java.security.SecureRandom;
import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.Objects;

import io.netty.buffer.ByteBuf;
import rpc.turbo.util.SystemClock;
import rpc.turbo.util.UnsafeStringUtils;
import rpc.turbo.util.concurrent.ConcurrentIntegerSequencer;

/**
 * 

* A globally unique identifier for objects. *

* *

* Consists of 12 bytes, divided as follows: *

* * * * * * * * * * * * * * * * * * * * * * *
ObjectID layout
01234567891011
timemachinepidinc
* *

* Instances of this class are immutable. *

* */ public final class ObjectId implements Serializable { private static final long serialVersionUID = -3433285147990005311L; private static final int LOW_ORDER_THREE_BYTES = 0x00FFFFFF; public final static long OFFSET_SECONDS = LocalDateTime.parse("2018-01-01T00:00:00").toEpochSecond(UTC); private static final long HEX32_PADDING = ByteBuffer.wrap("0000000000000000".getBytes()).getLong(); private static final int MACHINE_IDENTIFIER; private static final short PROCESS_IDENTIFIER; private static final long UNION_HIGH; private static final ConcurrentIntegerSequencer NEXT_COUNTER = new ConcurrentIntegerSequencer( new SecureRandom().nextInt()); public final int timestamp; public final long union; /** * Gets a new object id. * * @return the new id */ public static ObjectId next() { int next = NEXT_COUNTER.next() & LOW_ORDER_THREE_BYTES; long union = UNION_HIGH | next; return new ObjectId(currentSeconds(), union); } public ObjectId(final int timestamp, final long union) { this.timestamp = timestamp; this.union = union; } public ObjectId(final ByteBuf buffer) { Objects.requireNonNull(buffer, "buffer"); timestamp = buffer.readInt(); union = buffer.readLong(); } public int getTimestamp() { return timestamp; } public long getUnion() { return union; } public void writeTo(final ByteBuf buffer) { buffer.writeInt(timestamp); buffer.writeLong(union); } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + timestamp; result = prime * result + (int) (union ^ (union >>> 32)); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; ObjectId other = (ObjectId) obj; if (timestamp != other.timestamp) return false; if (union != other.union) return false; return true; } /** * 96位编码, 长度为24 * * @return */ public String toHexString() { byte[] bytes = new byte[24]; unsafe().putShort(bytes, ARRAY_BYTE_BASE_OFFSET + 0, byteToHexLE(timestamp >> 24)); unsafe().putShort(bytes, ARRAY_BYTE_BASE_OFFSET + 2, byteToHexLE(timestamp >> 16)); unsafe().putShort(bytes, ARRAY_BYTE_BASE_OFFSET + 4, byteToHexLE(timestamp >> 8)); unsafe().putShort(bytes, ARRAY_BYTE_BASE_OFFSET + 6, byteToHexLE(timestamp)); unsafe().putShort(bytes, ARRAY_BYTE_BASE_OFFSET + 8, byteToHexLE(union >> 52)); unsafe().putShort(bytes, ARRAY_BYTE_BASE_OFFSET + 10, byteToHexLE(union >> 48)); unsafe().putShort(bytes, ARRAY_BYTE_BASE_OFFSET + 12, byteToHexLE(union >> 40)); unsafe().putShort(bytes, ARRAY_BYTE_BASE_OFFSET + 14, byteToHexLE(union >> 32)); unsafe().putShort(bytes, ARRAY_BYTE_BASE_OFFSET + 16, byteToHexLE(union >> 24)); unsafe().putShort(bytes, ARRAY_BYTE_BASE_OFFSET + 18, byteToHexLE(union >> 16)); unsafe().putShort(bytes, ARRAY_BYTE_BASE_OFFSET + 20, byteToHexLE(union >> 8)); unsafe().putShort(bytes, ARRAY_BYTE_BASE_OFFSET + 22, byteToHexLE(union)); String hex = UnsafeStringUtils.toLatin1String(bytes); return hex; } /** * 128位编码, 长度为32, 前8个字符用'0'填充 * * @return */ public String toHexString32() { byte[] bytes = new byte[32]; unsafe().putLong(bytes, ARRAY_BYTE_BASE_OFFSET, HEX32_PADDING); unsafe().putShort(bytes, ARRAY_BYTE_BASE_OFFSET + 0 + 8, byteToHexLE(timestamp >> 24)); unsafe().putShort(bytes, ARRAY_BYTE_BASE_OFFSET + 2 + 8, byteToHexLE(timestamp >> 16)); unsafe().putShort(bytes, ARRAY_BYTE_BASE_OFFSET + 4 + 8, byteToHexLE(timestamp >> 8)); unsafe().putShort(bytes, ARRAY_BYTE_BASE_OFFSET + 6 + 8, byteToHexLE(timestamp)); unsafe().putShort(bytes, ARRAY_BYTE_BASE_OFFSET + 8 + 8, byteToHexLE(union >> 52)); unsafe().putShort(bytes, ARRAY_BYTE_BASE_OFFSET + 10 + 8, byteToHexLE(union >> 48)); unsafe().putShort(bytes, ARRAY_BYTE_BASE_OFFSET + 12 + 8, byteToHexLE(union >> 40)); unsafe().putShort(bytes, ARRAY_BYTE_BASE_OFFSET + 14 + 8, byteToHexLE(union >> 32)); unsafe().putShort(bytes, ARRAY_BYTE_BASE_OFFSET + 16 + 8, byteToHexLE(union >> 24)); unsafe().putShort(bytes, ARRAY_BYTE_BASE_OFFSET + 18 + 8, byteToHexLE(union >> 16)); unsafe().putShort(bytes, ARRAY_BYTE_BASE_OFFSET + 20 + 8, byteToHexLE(union >> 8)); unsafe().putShort(bytes, ARRAY_BYTE_BASE_OFFSET + 22 + 8, byteToHexLE(union)); String hex = UnsafeStringUtils.toLatin1String(bytes); return hex; } @Override public String toString() { return toHexString(); } static { try { MACHINE_IDENTIFIER = createMachineIdentifier(); PROCESS_IDENTIFIER = createProcessIdentifier(); UNION_HIGH = ((MACHINE_IDENTIFIER & 0xFF_FF_FFL) << 40) | ((PROCESS_IDENTIFIER & 0xFF_FFL) << 24); } catch (Exception e) { throw new RuntimeException(e); } } private static int createMachineIdentifier() { // build a 2-byte machine piece based on NICs info int machinePiece; try { StringBuilder sb = new StringBuilder(); Enumeration e = NetworkInterface.getNetworkInterfaces(); while (e.hasMoreElements()) { NetworkInterface ni = e.nextElement(); sb.append(ni.toString()); byte[] mac = ni.getHardwareAddress(); if (mac != null) { ByteBuffer bb = ByteBuffer.wrap(mac); try { sb.append(bb.getChar()); sb.append(bb.getChar()); sb.append(bb.getChar()); } catch (BufferUnderflowException shortHardwareAddressException) { // NOPMD // mac with less than 6 bytes. continue } } } machinePiece = sb.toString().hashCode(); } catch (Throwable t) { // exception sometimes happens with IBM JVM, use random machinePiece = (new SecureRandom().nextInt()); System.err.println("Failed to get machine identifier from network interface, using random number instead " + Arrays.toString(t.getStackTrace())); } machinePiece = machinePiece & LOW_ORDER_THREE_BYTES; return machinePiece; } // Creates the process identifier. This does not have to be unique per class // loader because // NEXT_COUNTER will provide the uniqueness. private static short createProcessIdentifier() { short processId; try { String processName = java.lang.management.ManagementFactory.getRuntimeMXBean().getName(); if (processName.contains("@")) { processId = (short) Integer.parseInt(processName.substring(0, processName.indexOf('@'))); } else { processId = (short) java.lang.management.ManagementFactory.getRuntimeMXBean().getName().hashCode(); } } catch (Throwable t) { processId = (short) new SecureRandom().nextInt(); System.err.println("Failed to get process identifier from JMX, using random number instead " + Arrays.toString(t.getStackTrace())); } return processId; } private static int currentSeconds() { return (int) (SystemClock.fast().seconds() - OFFSET_SECONDS); } public static void main(String[] args) { ObjectId id = next(); System.out.println(id.toHexString()); System.out.println(id.toHexString32()); while (true) { next(); } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy