namespace FoodLabeling.Th.Domain.Shared.Helpers;
///
/// 雪花 Id 生成器(项目规范:实体 string Id 使用 NextId().ToString())
///
public static class YitIdHelper
{
private const long Epoch = 1_609_459_200_000L;
private const int WorkerIdBits = 5;
private const int SequenceBits = 12;
private const long MaxSequence = (1L << SequenceBits) - 1;
private const int WorkerIdShift = SequenceBits;
private const int TimestampShift = SequenceBits + WorkerIdBits;
private const long WorkerId = 1;
private static long _lastTimestamp = -1L;
private static long _sequence;
private static readonly object SyncRoot = new();
///
/// 生成下一个雪花 Id
///
public static long NextId()
{
lock (SyncRoot)
{
var timestamp = CurrentTimestamp();
if (timestamp < _lastTimestamp)
{
timestamp = WaitNextMillis(_lastTimestamp);
}
if (_lastTimestamp == timestamp)
{
_sequence = (_sequence + 1) & MaxSequence;
if (_sequence == 0)
{
timestamp = WaitNextMillis(_lastTimestamp);
}
}
else
{
_sequence = 0;
}
_lastTimestamp = timestamp;
return ((timestamp - Epoch) << TimestampShift) | (WorkerId << WorkerIdShift) | _sequence;
}
}
private static long CurrentTimestamp() => DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
private static long WaitNextMillis(long lastTimestamp)
{
var timestamp = CurrentTimestamp();
while (timestamp <= lastTimestamp)
{
timestamp = CurrentTimestamp();
}
return timestamp;
}
}