diff --git a/C#.NET/source/Yitter.IdGenTest/Program.cs b/C#.NET/source/Yitter.IdGenTest/Program.cs
index 519a228..6805258 100644
--- a/C#.NET/source/Yitter.IdGenTest/Program.cs
+++ b/C#.NET/source/Yitter.IdGenTest/Program.cs
@@ -11,7 +11,7 @@ namespace Yitter.OrgSystem.TestA
class Program
{
// 测试参数(默认配置下,最佳性能是10W/s)
- static int genIdCount = 50000; // 计算ID数量(如果要验证50W效率,请将TopOverCostCount设置为20000或适当增加SeqBitLength)
+ static int genIdCount = 2;//50000; // 计算ID数量(如果要验证50W效率,请将TopOverCostCount设置为20000或适当增加SeqBitLength)
static short method = 1; // 1-漂移算法,2-传统算法
@@ -35,9 +35,12 @@ namespace Yitter.OrgSystem.TestA
WorkerIdBitLength = 6,
SeqBitLength = 6,
+ DataCenterIdBitLength = 10,
TopOverCostCount = 2000,
- //MinSeqNumber = 1,
+ //TimestampType = 1,
+
+ // MinSeqNumber = 1,
// MaxSeqNumber = 200,
// BaseTime = DateTime.Now.AddYears(-10),
@@ -128,6 +131,7 @@ namespace Yitter.OrgSystem.TestA
MinSeqNumber = options.MinSeqNumber,
MaxSeqNumber = options.MaxSeqNumber,
Method = options.Method,
+ //TimestampType = 1,
};
Console.WriteLine("Gen:" + i);
diff --git a/C#.NET/source/Yitter.IdGenerator/Contract/IdGeneratorOptions.cs b/C#.NET/source/Yitter.IdGenerator/Contract/IdGeneratorOptions.cs
index 9eb8430..1ff5c42 100644
--- a/C#.NET/source/Yitter.IdGenerator/Contract/IdGeneratorOptions.cs
+++ b/C#.NET/source/Yitter.IdGenerator/Contract/IdGeneratorOptions.cs
@@ -64,6 +64,22 @@ namespace Yitter.IdGenerator
public virtual int TopOverCostCount { get; set; } = 2000;
+ ///
+ /// 数据中心ID(默认0)
+ ///
+ public virtual uint DataCenterId { get; set; } = 0;
+
+ ///
+ /// 数据中心ID长度(默认0)
+ ///
+ public virtual byte DataCenterIdBitLength { get; set; } = 0;
+
+ ///
+ /// 时间戳类型(0-毫秒,1-秒),默认0
+ ///
+ public virtual byte TimestampType { get; set; } = 0;
+
+
public IdGeneratorOptions()
{
diff --git a/C#.NET/source/Yitter.IdGenerator/Core/SnowWorkerM1.cs b/C#.NET/source/Yitter.IdGenerator/Core/SnowWorkerM1.cs
index 1868e31..4344b5f 100644
--- a/C#.NET/source/Yitter.IdGenerator/Core/SnowWorkerM1.cs
+++ b/C#.NET/source/Yitter.IdGenerator/Core/SnowWorkerM1.cs
@@ -51,9 +51,9 @@ namespace Yitter.IdGenerator
///
/// 最大漂移次数(含)
///
- protected readonly int TopOverCostCount = 0;
+ protected int TopOverCostCount = 0;
- protected readonly byte _TimestampShift = 0;
+ protected byte _TimestampShift = 0;
protected static object _SyncLock = new object();
protected ushort _CurrentSeqNumber;
@@ -215,7 +215,7 @@ namespace Yitter.IdGenerator
_TurnBackIndex));
}
- private long NextOverCostId()
+ protected virtual long NextOverCostId()
{
long currentTimeTick = GetCurrentTimeTick();
@@ -262,7 +262,7 @@ namespace Yitter.IdGenerator
return CalcId(_LastTimeTick);
}
- private long NextNormalId()
+ protected virtual long NextNormalId()
{
long currentTimeTick = GetCurrentTimeTick();
@@ -319,7 +319,7 @@ namespace Yitter.IdGenerator
return CalcId(_LastTimeTick);
}
- private long CalcId(in long useTimeTick)
+ protected virtual long CalcId(in long useTimeTick)
{
var result = ((useTimeTick << _TimestampShift) +
((long)WorkerId << SeqBitLength) +
@@ -329,7 +329,7 @@ namespace Yitter.IdGenerator
return result;
}
- private long CalcTurnBackId(in long useTimeTick)
+ protected virtual long CalcTurnBackId(in long useTimeTick)
{
var result = ((useTimeTick << _TimestampShift) +
((long)WorkerId << SeqBitLength) + _TurnBackIndex);
diff --git a/C#.NET/source/Yitter.IdGenerator/Core/SnowWorkerM3.cs b/C#.NET/source/Yitter.IdGenerator/Core/SnowWorkerM3.cs
new file mode 100644
index 0000000..6bab285
--- /dev/null
+++ b/C#.NET/source/Yitter.IdGenerator/Core/SnowWorkerM3.cs
@@ -0,0 +1,83 @@
+/*
+ * 版权属于:yitter(yitter@126.com)
+ * 开源地址:https://github.com/yitter/idgenerator
+ * 版权协议:MIT
+ * 版权说明:只要保留本版权,你可以免费使用、修改、分发本代码。
+ * 免责条款:任何因为本代码产生的系统、法律、政治、宗教问题,均与版权所有者无关。
+ *
+ */
+
+using System;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace Yitter.IdGenerator
+{
+ ///
+ /// 雪花漂移算法(支持数据中心ID和秒级时间戳)
+ ///
+ internal class SnowWorkerM3 : SnowWorkerM1
+ {
+ ///
+ /// 数据中心ID(默认0)
+ ///
+ protected readonly uint DataCenterId = 0;
+
+ ///
+ /// 数据中心ID长度(默认0)
+ ///
+ protected readonly byte DataCenterIdBitLength = 0;
+
+ ///
+ /// 时间戳类型(0-毫秒,1-秒),默认0
+ ///
+ protected readonly byte TimestampType = 0;
+
+
+ public SnowWorkerM3(IdGeneratorOptions options) : base(options)
+ {
+ // 秒级时间戳类型
+ TimestampType = options.TimestampType;
+
+ // DataCenter相关
+ DataCenterId = options.DataCenterId;
+ DataCenterIdBitLength = options.DataCenterIdBitLength;
+
+ if (TimestampType == 1)
+ {
+ TopOverCostCount = 0;
+ }
+ _TimestampShift = (byte)(DataCenterIdBitLength + WorkerIdBitLength + SeqBitLength);
+ }
+
+ protected override long CalcId(in long useTimeTick)
+ {
+ var result = ((useTimeTick << _TimestampShift) +
+ ((long)DataCenterId << DataCenterIdBitLength) +
+ ((long)WorkerId << SeqBitLength) +
+ (long)_CurrentSeqNumber);
+
+ _CurrentSeqNumber++;
+ return result;
+ }
+
+ protected override long CalcTurnBackId(in long useTimeTick)
+ {
+ var result = ((useTimeTick << _TimestampShift) +
+ ((long)DataCenterId << DataCenterIdBitLength) +
+ ((long)WorkerId << SeqBitLength) +
+ _TurnBackIndex);
+
+ _TurnBackTimeTick--;
+ return result;
+ }
+
+ protected override long GetCurrentTimeTick()
+ {
+ return TimestampType == 0 ?
+ (long)(DateTime.UtcNow - BaseTime).TotalMilliseconds :
+ (long)(DateTime.UtcNow - BaseTime).TotalSeconds;
+ }
+
+ }
+}
diff --git a/C#.NET/source/Yitter.IdGenerator/DefaultIdGenerator.cs b/C#.NET/source/Yitter.IdGenerator/DefaultIdGenerator.cs
index f74adb9..ab450f1 100644
--- a/C#.NET/source/Yitter.IdGenerator/DefaultIdGenerator.cs
+++ b/C#.NET/source/Yitter.IdGenerator/DefaultIdGenerator.cs
@@ -46,12 +46,12 @@ namespace Yitter.IdGenerator
{
throw new ApplicationException("WorkerIdBitLength error.(range:[1, 21])");
}
- if (options.SeqBitLength + options.WorkerIdBitLength > 22)
+ if (options.DataCenterIdBitLength + options.WorkerIdBitLength + options.SeqBitLength > 22)
{
- throw new ApplicationException("error:WorkerIdBitLength + SeqBitLength <= 22");
+ throw new ApplicationException("error:DataCenterIdBitLength + WorkerIdBitLength + SeqBitLength <= 22");
}
- // 3.WorkerId
+ // 3.WorkerId & DataCenterId
var maxWorkerIdNumber = (1 << options.WorkerIdBitLength) - 1;
if (maxWorkerIdNumber == 0)
{
@@ -62,6 +62,12 @@ namespace Yitter.IdGenerator
throw new ApplicationException("WorkerId error. (range:[0, " + maxWorkerIdNumber + "]");
}
+ var maxDataCenterIdNumber = (1 << options.DataCenterIdBitLength) - 1;
+ if (options.DataCenterId < 0 || options.DataCenterId > maxDataCenterIdNumber)
+ {
+ throw new ApplicationException("DataCenterId error. (range:[0, " + maxDataCenterIdNumber + "]");
+ }
+
// 4.SeqBitLength
if (options.SeqBitLength < 2 || options.SeqBitLength > 21)
{
@@ -87,18 +93,22 @@ namespace Yitter.IdGenerator
switch (options.Method)
{
- case 1:
- _SnowWorker = new SnowWorkerM1(options);
- break;
case 2:
_SnowWorker = new SnowWorkerM2(options);
break;
default:
- _SnowWorker = new SnowWorkerM1(options);
+ if (options.DataCenterIdBitLength == 0 && options.TimestampType == 0)
+ {
+ _SnowWorker = new SnowWorkerM1(options);
+ }
+ else
+ {
+ _SnowWorker = new SnowWorkerM3(options);
+ }
break;
}
- if (options.Method == 1)
+ if (options.Method != 2)
{
Thread.Sleep(500);
}
diff --git a/README.md b/README.md
index 81cc731..b82dabc 100644
--- a/README.md
+++ b/README.md
@@ -146,7 +146,7 @@ QQ群:646049993
❄ ***WorkerIdBitLength***,机器码位长,决定 WorkerId 的最大值,**默认值6**,取值范围 [1, 19],实际上有些语言采用 无符号 ushort (uint16) 类型接收该参数,所以最大值是16,如果是采用 有符号 short (int16),则最大值为15。
-❄ **WorkerId**,机器码,**最重要参数**,无默认值,必须 **全局唯一**,必须 **程序设定**,缺省条件(WorkerIdBitLength取默认值)时最大值63,理论最大值 2^WorkerIdBitLength-1(不同实现语言可能会限定在 65535 或 32767,原理同 WorkerIdBitLength 规则)。不同机器或不同应用实例 **不能相同**,你可通过应用程序配置该值,也可通过调用外部服务获取值。针对自动注册WorkerId需求,本算法提供默认实现:通过 redis 自动注册 WorkerId 的动态库,详见“Tools\AutoRegisterWorkerId”。
+❄ **WorkerId**,机器码,**最重要参数**,无默认值,必须 **全局唯一**(或相同 DataCenterId 内唯一),必须 **程序设定**,缺省条件(WorkerIdBitLength取默认值)时最大值63,理论最大值 2^WorkerIdBitLength-1(不同实现语言可能会限定在 65535 或 32767,原理同 WorkerIdBitLength 规则)。不同机器或不同应用实例 **不能相同**,你可通过应用程序配置该值,也可通过调用外部服务获取值。针对自动注册WorkerId需求,本算法提供默认实现:通过 redis 自动注册 WorkerId 的动态库,详见“Tools\AutoRegisterWorkerId”。
**特别提示**:如果一台服务器部署多个独立服务,需要为每个服务指定不同的 WorkerId。
@@ -158,6 +158,14 @@ QQ群:646049993
❄ ***BaseTime***,基础时间(也称:基点时间、原点时间、纪元时间),有默认值(2020年),是毫秒时间戳(是整数,.NET是DatetTime类型),作用是:用生成ID时的系统时间与基础时间的差值(毫秒数)作为生成ID的时间戳。基础时间一般无需设置,如果觉得默认值太老,你可以重新设置,不过要注意,这个值以后最好不变。
+第二版增加参数(非必须):
+
+❄ ***DataCenterId***,数据中心ID(默认0),请确保全局唯一。
+
+❄ ***DataCenterIdBitLength***,数据中心ID长度(默认0)。
+
+❄ ***TimestampType***,时间戳类型(0-毫秒,1-秒),默认0。
+
#### 常规集成