namespace OSS.Tools.Num;
///
/// 数字编号生成基类
///
public class BaseSnowNumGenerator
{
//【sequence 部分】 随机序列
private long _maxSequence; // 最大值
private int _sequenceBitLength; //长度
// 【WorkId部分】 工作Id
private long _maxWorkerId; // 最大值
private int _workerIdBitLength; // 长度
///
/// workerId需要偏移的位置
///
protected int WorkerLeftShift { get; private set; }
///
/// Timestamp 需要偏移的位置
///
protected int TimestampLeftShift { get; private set; }
private void InitialConfig(int seqBitLength, int worIdBitLength)
{
_sequenceBitLength = seqBitLength;
_maxSequence = -1L ^ (-1L << _sequenceBitLength);
_workerIdBitLength = worIdBitLength;
_maxWorkerId = -1L ^ (-1L << _workerIdBitLength);
WorkerLeftShift = _sequenceBitLength;
TimestampLeftShift = WorkerLeftShift + _workerIdBitLength;
}
///
/// 获取当前的工作ID
///
public long WorkId { get; internal set; }
private long _sequence; // 时间戳下 序号值
private long _timestamp; // 最后一次的时间戳值
private readonly object obj = new object(); //
///
/// 构造函数
///
protected BaseSnowNumGenerator(int workId, int seqBitLength, int worIdBitLength)
{
InitialConfig(seqBitLength, worIdBitLength);
if (workId > _maxWorkerId || workId < 0)
{
throw new ArgumentException("workId", $"工作Id不能大于 {_maxWorkerId} 或 小于 0");
}
WorkId = workId;
}
///
/// 生成编号
///
///
public long NewNum()
{
long ts, seq;
lock (obj)
{
SetTimestampAndSeq();
ts = _timestamp;
seq = _sequence;
}
return CombineNum(ts, seq);
}
///
/// 组合数字ID
///
///
///
///
private long CombineNum(long timestamp, long sequence)
{
return (timestamp << TimestampLeftShift) | (WorkId << WorkerLeftShift) | sequence;
}
private void SetTimestampAndSeq()
{
var newTimestamp = TimeMilliNum();
if (newTimestamp < _timestamp)
{
//如果当前时间小于上一次ID生成的时间戳,说明系统时钟回退过这个时候应当抛出异常
throw new ArgumentException(
$"当前时间小于上次生成时间 {_timestamp - newTimestamp} 毫秒,注意系统时间是否发生变化!");
}
// 如果是同一时间生成的,则进行毫秒内序列
if (_timestamp == newTimestamp)
{
_sequence = (_sequence + 1) & _maxSequence;
//毫秒内序列溢出
//阻塞到下一个毫秒,获得新的时间戳
if (_sequence == 0)
newTimestamp = WaitNextMillis(_timestamp);
}
//时间戳改变,毫秒内序列重置
else
_sequence = 0L;
_timestamp = newTimestamp;
}
///
/// 当前毫秒内序列使用完,等待下一毫秒
///
///
protected long WaitNextMillis(long curTimeSpan)
{
long timeTicks;
do
{
timeTicks = TimeMilliNum();
} while (timeTicks <= curTimeSpan);
return timeTicks;
}
private static readonly long _timeStartTicks = new DateTime(2020, 1, 1).ToUniversalTime().Ticks;
///
/// 时间戳数字编号(精度 毫秒
///
///
private static long TimeMilliNum()
{
return (DateTime.UtcNow.Ticks - _timeStartTicks) / 10000;
}
}