60 lines
2.0 KiB
C#
60 lines
2.0 KiB
C#
using F9WebAiTest.Application.Interfaces.SnowflakeID;
|
|
|
|
namespace F9WebAiTest.Infrastructure.InterfaceImplements.SnowflakeID;
|
|
|
|
/// <summary>
|
|
/// 雪花 ID 生成器(自实现,41 时间戳 + 10 worker + 12 序列)。
|
|
/// 参考 BBIT.F9.Infrastructure.InterfaceImplements.SnowflakeID.SnowflakeIdGenerator
|
|
/// </summary>
|
|
public class SnowflakeIdGenerator : ISnowflakeIdGenerator
|
|
{
|
|
private readonly object _lock = new();
|
|
private readonly long _workerId;
|
|
private readonly long _epoch;
|
|
private long _lastTimestamp = -1L;
|
|
private long _sequence;
|
|
|
|
private const long WorkerIdBits = 10L;
|
|
private const long SequenceBits = 12L;
|
|
private const long WorkerIdShift = SequenceBits;
|
|
private const long TimestampShift = SequenceBits + WorkerIdBits;
|
|
private const long SequenceMask = -1L ^ (-1L << (int)SequenceBits);
|
|
|
|
public SnowflakeIdGenerator()
|
|
{
|
|
_workerId = 1; // 单节点默认 workerId = 1
|
|
_epoch = new DateTimeOffset(2025, 10, 1, 0, 0, 0, TimeSpan.Zero).ToUnixTimeMilliseconds();
|
|
}
|
|
|
|
public long CreateId()
|
|
{
|
|
lock (_lock)
|
|
{
|
|
var timestamp = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds() - _epoch;
|
|
if (timestamp < _lastTimestamp)
|
|
throw new InvalidOperationException("时钟回拨,拒绝生成 ID");
|
|
|
|
if (timestamp == _lastTimestamp)
|
|
{
|
|
_sequence = (_sequence + 1) & SequenceMask;
|
|
if (_sequence == 0)
|
|
{
|
|
// 序列溢出,等待下一毫秒
|
|
while (timestamp <= _lastTimestamp)
|
|
timestamp = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds() - _epoch;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
_sequence = 0;
|
|
}
|
|
|
|
_lastTimestamp = timestamp;
|
|
|
|
return (timestamp << (int)TimestampShift)
|
|
| (_workerId << (int)WorkerIdShift)
|
|
| _sequence;
|
|
}
|
|
}
|
|
}
|