cn.vonce.sql.uitls.SnowflakeId16 Maven / Gradle / Ivy
Show all versions of vonce-sqlbean-core Show documentation
package cn.vonce.sql.uitls;
//import org.slf4j.Logger;
//import org.slf4j.LoggerFactory;
import java.io.Serializable;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
import java.util.concurrent.RunnableFuture;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* 廖雪峰的 53 bits unique id:
* 53bitID由32bit秒级时间戳+16bit自增+5bit机器标识组成,累积32台机器,每秒可以生成6.5万个序列号
*
* |--------|--------|--------|--------|--------|--------|--------|--------|
* |00000000|00011111|11111111|11111111|11111111|11111111|11111111|11111111|
* |--------|---xxxxx|xxxxxxxx|xxxxxxxx|xxxxxxxx|xxx-----|--------|--------|
* |--------|--------|--------|--------|--------|---xxxxx|xxxxxxxx|xxx-----|
* |--------|--------|--------|--------|--------|--------|--------|---xxxxx|
*
* Maximum ID = 11111_11111111_11111111_11111111_11111111_11111111_11111111
*
* Maximum TS = 11111_11111111_11111111_11111111_111
*
* Maximum NT = ----- -------- -------- -------- ---11111_11111111_111 = 65535
*
* Maximum SH = ----- -------- -------- -------- -------- -------- ---11111 = 31
*
* It can generate 64k unique id per IP and up to 2106-02-07T06:28:15Z.
*/
public final class SnowflakeId16 implements Serializable {
// private static final Logger logger = LoggerFactory.getLogger(SnowflakeId16.class);
private static final Pattern PATTERN_LONG_ID = Pattern.compile("^([0-9]{15})([0-9a-f]{32})([0-9a-f]{3})$");
private static final Pattern PATTERN_HOSTNAME = Pattern.compile("^.*\\D+([0-9]+)$");
//暂时不支持jdk8
//private static final long OFFSET = LocalDate.of(2000, 1, 1).atStartOfDay(ZoneId.of("Z")).toEpochSecond();
private static final long OFFSET = 946684800;
private static final long MAX_NEXT = 0b11111_11111111_111L;
private static final long SHARD_ID = getServerIdAsLong();
private static long offset = 0;
private static long lastEpoch = 0;
public static long nextId() {
return nextId(System.currentTimeMillis() / 1000);
}
private static synchronized long nextId(long epochSecond) {
if (epochSecond < lastEpoch) {
// warning: clock is turn back:
// logger.warn("clock is back: " + epochSecond + " from previous:" + lastEpoch);
epochSecond = lastEpoch;
}
if (lastEpoch != epochSecond) {
lastEpoch = epochSecond;
reset();
}
offset++;
long next = offset & MAX_NEXT;
if (next == 0) {
// logger.warn("maximum id reached in 1 second in epoch: " + epochSecond);
return nextId(epochSecond + 1);
}
return generateId(epochSecond, next, SHARD_ID);
}
private static void reset() {
offset = 0;
}
private static long generateId(long epochSecond, long next, long shardId) {
return ((epochSecond - OFFSET) << 21) | (next << 5) | shardId;
}
private static long getServerIdAsLong() {
try {
//为照顾安卓版需异步调用
RunnableFuture runnableFuture = new FutureTask<>(new Callable() {
@Override
public String call() throws UnknownHostException {
return InetAddress.getLocalHost().getHostName();
}
});
new Thread(runnableFuture).start();
String hostname = runnableFuture.get();
Matcher matcher = PATTERN_HOSTNAME.matcher(hostname);
if (matcher.matches()) {
long n = Long.parseLong(matcher.group(1));
if (n >= 0 && n < 8) {
// logger.info("detect server id from host name {}: {}.", hostname, n);
return n;
}
}
} catch (ExecutionException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
return 0;
}
public static long stringIdToLongId(String stringId) {
// a stringId id is composed as timestamp (15) + uuid (32) + serverId (000~fff).
Matcher matcher = PATTERN_LONG_ID.matcher(stringId);
if (matcher.matches()) {
long epoch = Long.parseLong(matcher.group(1)) / 1000;
String uuid = matcher.group(2);
byte[] sha1 = HashUtil.sha1AsBytes(uuid);
long next = ((sha1[0] << 24) | (sha1[1] << 16) | (sha1[2] << 8) | sha1[3]) & MAX_NEXT;
long serverId = Long.parseLong(matcher.group(3), 16);
return generateId(epoch, next, serverId);
}
throw new IllegalArgumentException("Invalid id: " + stringId);
}
}