void Main()
{
var id = new XID.Info(271103830593110952);
id.Dump();
}
// You can define other methods, fields, classes and namespaces here
public static class XID
{
private static long workerId = 0; //机器ID
private static long sequence = 0L;
private static long lastTimestamp = -1L;
private static readonly int workerIdBits = 10; //机器码字节数。10个字节用来保存机器码(定义为Long类型会出现,最大偏移64位,所以左移64位没有意义)
private static readonly int sequenceBits = 22 - workerIdBits; //计数器字节数,12个字节用来保存计数码
private static readonly int sequenceShift = workerIdBits; //机器码数据左移位数,就是后面计数器占用的位数
private static readonly int timestampLeftShift = sequenceBits + workerIdBits; //时间戳左移动位数就是机器码和计数器总字节数
private static readonly long workerIdMax = -1L ^ -1L << workerIdBits; //最大WorkId
private static readonly long sequenceMax = -1L ^ -1L << sequenceBits; //一微秒内可以产生计数,如果达到该值则等到下一微妙在进行生成
private static readonly object lockObj = new object();
private static readonly DateTime start_base_time = new DateTime(2020, 1, 1, 0, 0, 0, DateTimeKind.Utc);
/// <summary>
/// 设置机器码
/// </summary>
/// <param name="id">机器码</param>
public static void Initialize(string data)
{
long.TryParse(data, out workerId);
}
public static long Nextval
{
get
{
lock (lockObj)
{
return nextId();
}
}
}
private static long nextId()
{
if (workerId < 1)
{
workerId = 1982;
}
workerId = workerId & workerIdMax;
long timestamp = timeGen();
if (lastTimestamp == timestamp)
{
//同一微妙中生成ID
var abc = (sequence + 1) & sequenceMax; //用&运算计算该微秒内产生的计数是否已经到达上限
if (abc == 0)
{
//一微妙内产生的ID计数已达上限,等待下一微妙
timestamp = tillNextMillis(lastTimestamp);
}
sequence = abc;
}
else
{
//不同微秒生成ID
sequence = 0; //计数清0
}
if (timestamp < lastTimestamp)
{
//如果当前时间戳比上一次生成ID时时间戳还小,抛出异常,因为不能保证现在生成的ID之前没有生成过
throw new Exception(string.Format("Clock moved backwards. Refusing to generate id for {0} milliseconds",
lastTimestamp - timestamp));
}
lastTimestamp = timestamp; //把当前时间戳保存为最后生成ID的时间戳
long nextId = timestamp << timestampLeftShift | sequence << sequenceShift | workerId;
return nextId;
}
/// <summary>
/// 获取下一微秒时间戳
/// </summary>
/// <param name="lastTimestamp"></param>
/// <returns></returns>
private static long tillNextMillis(long lastTimestamp)
{
long timestamp = timeGen();
while (timestamp <= lastTimestamp)
{
timestamp = timeGen();
}
return timestamp;
}
/// <summary>
/// 生成当前时间戳
/// </summary>
/// <returns></returns>
private static long timeGen()
{
return (long)(DateTime.UtcNow - start_base_time).TotalMilliseconds;
}
public class Info
{
public Info(long id)
{
var size = 64;
//size = System.Runtime.InteropServices.Marshal.SizeOf(id) * 8;
this.Timestamp = id >> timestampLeftShift;
this.CreateTime = start_base_time.AddMilliseconds(this.Timestamp);
var timeLen = (size - timestampLeftShift);
this.SequenceId = id << timeLen >> timeLen >> sequenceShift;
this.WorkerId = id & ((1 << sequenceShift) - 1);
}
public DateTime CreateTime { get; set; }
public long Timestamp { get; set; }
public long SequenceId { get; set; }
public long WorkerId { get; set; }
}
}