/*
* Copyright 1999-2015 dangdang.com.
* <p>
* 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.
* </p>
*/
package com.dangdang.ddframe.rdb.sharding.id.generator.self;
import com.dangdang.ddframe.rdb.sharding.id.generator.IdGenerator;
import com.dangdang.ddframe.rdb.sharding.id.generator.self.time.AbstractClock;
import com.google.common.base.Preconditions;
import com.google.common.base.Strings;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
/**
* 自生成Id生成器.
*
* <p>
* 长度为64bit,从高位到低位依次为
* </p>
*
* <pre>
* 1bit 符号位
* 41bits 时间偏移量从2016年11月1日零点到现在的毫秒数
* 10bits 工作进程Id
* 12bits 同一个毫秒内的自增量
* </pre>
*
* <p>
* 工作进程Id获取优先级: 系统变量{@code sjdbc.self.id.generator.worker.id} 大于 环境变量{@code SJDBC_SELF_ID_GENERATOR_WORKER_ID}
* ,另外可以调用@{@code CommonSelfIdGenerator.setWorkerId}进行设置
* </p>
*
* @author gaohongtao
*/
@Getter
@Slf4j
public class CommonSelfIdGenerator implements IdGenerator {
public static final long SJDBC_EPOCH;
private static final long SEQUENCE_BITS = 12L;
private static final long WORKER_ID_BITS = 10L;
private static final long SEQUENCE_MASK = (1 << SEQUENCE_BITS) - 1;
private static final long WORKER_ID_LEFT_SHIFT_BITS = SEQUENCE_BITS;
private static final long TIMESTAMP_LEFT_SHIFT_BITS = WORKER_ID_LEFT_SHIFT_BITS + WORKER_ID_BITS;
private static final long WORKER_ID_MAX_VALUE = 1L << WORKER_ID_BITS;
@Setter
private static AbstractClock clock = AbstractClock.systemClock();
@Getter
private static long workerId;
static {
Calendar calendar = Calendar.getInstance();
calendar.set(2016, Calendar.NOVEMBER, 1);
calendar.set(Calendar.HOUR_OF_DAY, 0);
calendar.set(Calendar.MINUTE, 0);
calendar.set(Calendar.SECOND, 0);
calendar.set(Calendar.MILLISECOND, 0);
SJDBC_EPOCH = calendar.getTimeInMillis();
initWorkerId();
}
private long sequence;
private long lastTime;
static void initWorkerId() {
String workerId = System.getProperty("sjdbc.self.id.generator.worker.id");
if (!Strings.isNullOrEmpty(workerId)) {
setWorkerId(Long.valueOf(workerId));
return;
}
workerId = System.getenv("SJDBC_SELF_ID_GENERATOR_WORKER_ID");
if (Strings.isNullOrEmpty(workerId)) {
return;
}
setWorkerId(Long.valueOf(workerId));
}
/**
* 设置工作进程Id.
*
* @param workerId 工作进程Id
*/
public static void setWorkerId(final Long workerId) {
Preconditions.checkArgument(workerId >= 0L && workerId < WORKER_ID_MAX_VALUE);
CommonSelfIdGenerator.workerId = workerId;
}
/**
* 生成Id.
*
* @return 返回@{@link Long}类型的Id
*/
@Override
public synchronized Number generateId() {
long time = clock.millis();
Preconditions.checkState(lastTime <= time, "Clock is moving backwards, last time is %d milliseconds, current time is %d milliseconds", lastTime, time);
if (lastTime == time) {
if (0L == (sequence = ++sequence & SEQUENCE_MASK)) {
time = waitUntilNextTime(time);
}
} else {
sequence = 0;
}
lastTime = time;
if (log.isDebugEnabled()) {
log.debug("{}-{}-{}", new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS").format(new Date(lastTime)), workerId, sequence);
}
return ((time - SJDBC_EPOCH) << TIMESTAMP_LEFT_SHIFT_BITS) | (workerId << WORKER_ID_LEFT_SHIFT_BITS) | sequence;
}
private long waitUntilNextTime(final long lastTime) {
long time = clock.millis();
while (time <= lastTime) {
time = clock.millis();
}
return time;
}
}