Browse Source

Add SnowflakeId generator class.

master
Savorboard 6 years ago
parent
commit
c5b0b67811
1 changed files with 93 additions and 0 deletions
  1. +93
    -0
      src/DotNetCore.CAP/Infrastructure/SnowflakeId.cs

+ 93
- 0
src/DotNetCore.CAP/Infrastructure/SnowflakeId.cs View File

@@ -0,0 +1,93 @@
// Copyright 2010-2012 Twitter, Inc.
// An object that generates IDs. This is broken into a separate class in case we ever want to support multiple worker threads per process

using System;

namespace DotNetCore.CAP.Infrastructure
{
public class SnowflakeId
{
public const long Twepoch = 1288834974657L;

private const int WorkerIdBits = 5;
private const int DatacenterIdBits = 5;
private const int SequenceBits = 12;
private const long MaxWorkerId = -1L ^ (-1L << WorkerIdBits);
private const long MaxDatacenterId = -1L ^ (-1L << DatacenterIdBits);

private const int WorkerIdShift = SequenceBits;
private const int DatacenterIdShift = SequenceBits + WorkerIdBits;
public const int TimestampLeftShift = SequenceBits + WorkerIdBits + DatacenterIdBits;
private const long SequenceMask = -1L ^ (-1L << SequenceBits);

private static SnowflakeId _snowflakeId;

private readonly object _lock = new object();
private long _lastTimestamp = -1L;

private SnowflakeId(long workerId, long datacenterId, long sequence = 0L)
{
WorkerId = workerId;
DatacenterId = datacenterId;
Sequence = sequence;

// sanity check for workerId
if (workerId > MaxWorkerId || workerId < 0)
throw new ArgumentException($"worker Id can't be greater than {MaxWorkerId} or less than 0");

if (datacenterId > MaxDatacenterId || datacenterId < 0)
throw new ArgumentException($"datacenter Id can't be greater than {MaxDatacenterId} or less than 0");
}

public long WorkerId { get; protected set; }
public long DatacenterId { get; protected set; }

public long Sequence { get; internal set; }

public static SnowflakeId Default(long datacenterId = 0)
{
return _snowflakeId ?? (_snowflakeId = new SnowflakeId(AppDomain.CurrentDomain.Id, datacenterId));
}

public virtual long NextId()
{
lock (_lock)
{
var timestamp = TimeGen();

if (timestamp < _lastTimestamp)
throw new Exception(
$"InvalidSystemClock: Clock moved backwards, Refusing to generate id for {_lastTimestamp - timestamp} milliseconds");

if (_lastTimestamp == timestamp)
{
Sequence = (Sequence + 1) & SequenceMask;
if (Sequence == 0) timestamp = TilNextMillis(_lastTimestamp);
}
else
{
Sequence = 0;
}

_lastTimestamp = timestamp;
var id = ((timestamp - Twepoch) << TimestampLeftShift) |
(DatacenterId << DatacenterIdShift) |
(WorkerId << WorkerIdShift) | Sequence;

return id;
}
}

protected virtual long TilNextMillis(long lastTimestamp)
{
var timestamp = TimeGen();
while (timestamp <= lastTimestamp) timestamp = TimeGen();
return timestamp;
}

protected virtual long TimeGen()
{
return DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
}
}
}

Loading…
Cancel
Save