7
.gitignore
vendored
7
.gitignore
vendored
@@ -257,3 +257,10 @@ target/
|
||||
|
||||
# macOS
|
||||
.DS_Store
|
||||
D/test/test
|
||||
D/libyitterd.a
|
||||
D/dub.*.json
|
||||
*/.dub/*
|
||||
*/test/.dub/*
|
||||
C/source/build/*
|
||||
D/test/dub.*.json
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
cmake_minimum_required(VERSION 3.17)
|
||||
cmake_minimum_required(VERSION 3.13)
|
||||
project(YitIdGen)
|
||||
set(CMAKE_C_STANDARD 11)
|
||||
|
||||
@@ -8,6 +8,7 @@ set(CMAKE_C_STANDARD 11)
|
||||
aux_source_directory(. DIR_SRCS)
|
||||
add_subdirectory(idgen)
|
||||
|
||||
|
||||
#编译动态库
|
||||
#set(LIB_SRC YitIdHelper.h YitIdHelper.c)
|
||||
#add_library(YitIdGenLib SHARED ${LIB_SRC})
|
||||
@@ -21,7 +22,7 @@ add_subdirectory(idgen)
|
||||
set(LIB_SRC YitIdHelper.h YitIdHelper.c)
|
||||
add_library(YitIdHelper ${LIB_SRC})
|
||||
add_executable(YitIdGen main.c)
|
||||
target_link_libraries(YitIdGen YitIdHelper)
|
||||
target_link_libraries(YitIdGen idgen)
|
||||
target_link_libraries(YitIdGen YitIdHelper pthread)
|
||||
target_link_libraries(YitIdGen idgen pthread)
|
||||
|
||||
|
||||
|
||||
32
D/README.md
Normal file
32
D/README.md
Normal file
@@ -0,0 +1,32 @@
|
||||
|
||||
## 运行环境
|
||||
|
||||
```sh
|
||||
$ cd test
|
||||
$ dub run --compiler=dmd -a=x86_64
|
||||
```
|
||||
|
||||
|
||||
## 调用示例(D)
|
||||
|
||||
第1步,**全局** 初始化(应用程序启动时执行一次):
|
||||
```
|
||||
// 创建 IdGeneratorOptions 对象,请在构造函数中输入 WorkerId:
|
||||
IdGeneratorOptions options = new IdGeneratorOptions(1);
|
||||
// options.WorkerIdBitLength = 10; // WorkerIdBitLength 默认值6,支持的 WorkerId 最大值为2^6-1,若 WorkerId 超过64,可设置更大的 WorkerIdBitLength
|
||||
// ...... 其它参数设置参考 IdGeneratorOptions 定义,一般来说,只要再设置 WorkerIdBitLength (决定 WorkerId 的最大值)。
|
||||
|
||||
// 保存参数(必须的操作,否则以上设置都不能生效):
|
||||
YitIdHelper.setIdGenerator(options);
|
||||
// 以上初始化过程只需全局一次,且必须在第2步之前设置。
|
||||
```
|
||||
|
||||
第2步,生成ID:
|
||||
```
|
||||
// 初始化以后,即可在任何需要生成ID的地方,调用以下方法:
|
||||
long newId = YitIdHelper.nextId();
|
||||
```
|
||||
|
||||
如果基于DI框架集成,可以参考 YitIdHelper 去管理 IdGenerator 对象,须使用 **单例** 模式。
|
||||
|
||||
|
||||
9
D/dub.json
Normal file
9
D/dub.json
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"authors": [
|
||||
"yitter",
|
||||
"HuntLabs"
|
||||
],
|
||||
"description": "A minimal D application.",
|
||||
"license": "proprietary",
|
||||
"name": "yitterd"
|
||||
}
|
||||
9
D/source/yitter/contract/IIdGenerator.d
Normal file
9
D/source/yitter/contract/IIdGenerator.d
Normal file
@@ -0,0 +1,9 @@
|
||||
/*
|
||||
* 版权属于:yitter(yitter@126.com)
|
||||
* 开源地址:https://gitee.com/yitter/idgenerator
|
||||
*/
|
||||
module yitter.contract.IIdGenerator;
|
||||
|
||||
interface IIdGenerator {
|
||||
long newLong();
|
||||
}
|
||||
9
D/source/yitter/contract/ISnowWorker.d
Normal file
9
D/source/yitter/contract/ISnowWorker.d
Normal file
@@ -0,0 +1,9 @@
|
||||
/*
|
||||
* 版权属于:yitter(yitter@126.com)
|
||||
* 开源地址:https://gitee.com/yitter/idgenerator
|
||||
*/
|
||||
module yitter.contract.ISnowWorker;
|
||||
|
||||
interface ISnowWorker {
|
||||
long nextId();
|
||||
}
|
||||
29
D/source/yitter/contract/IdGeneratorException.d
Normal file
29
D/source/yitter/contract/IdGeneratorException.d
Normal file
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* 版权属于:yitter(yitter@126.com)
|
||||
* 开源地址:https://gitee.com/yitter/idgenerator
|
||||
*/
|
||||
module yitter.contract.IdGeneratorException;
|
||||
|
||||
class IdGeneratorException : Exception {
|
||||
|
||||
// this() {
|
||||
// super();
|
||||
// }
|
||||
|
||||
this(string message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
// this(Throwable cause) {
|
||||
// super(cause);
|
||||
// }
|
||||
|
||||
this(string message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
// this(string msgFormat, Object... args) {
|
||||
// super(string.format(msgFormat, args));
|
||||
// }
|
||||
|
||||
}
|
||||
72
D/source/yitter/contract/IdGeneratorOptions.d
Normal file
72
D/source/yitter/contract/IdGeneratorOptions.d
Normal file
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* 版权属于:yitter(yitter@126.com)
|
||||
* 开源地址:https://gitee.com/yitter/idgenerator
|
||||
*/
|
||||
module yitter.contract.IdGeneratorOptions;
|
||||
|
||||
import std.datetime;
|
||||
|
||||
/**
|
||||
* 雪花算法使用的参数
|
||||
* 参数说明,参考 README.md 的 “配置参数” 章节。
|
||||
*/
|
||||
class IdGeneratorOptions {
|
||||
|
||||
/**
|
||||
* 雪花计算方法
|
||||
* (1-漂移算法|2-传统算法),默认1
|
||||
*/
|
||||
short Method = 1;
|
||||
|
||||
/**
|
||||
* 基础时间(ms单位)
|
||||
* 不能超过当前系统时间
|
||||
*/
|
||||
// long BaseTime = 1582136402000L;
|
||||
SysTime BaseTime;
|
||||
|
||||
/**
|
||||
* 机器码
|
||||
* 必须由外部设定,最大值 2^WorkerIdBitLength-1
|
||||
*/
|
||||
short WorkerId = 0;
|
||||
|
||||
/**
|
||||
* 机器码位长
|
||||
* 默认值6,取值范围 [1, 15](要求:序列数位长+机器码位长不超过22)
|
||||
*/
|
||||
byte WorkerIdBitLength = 6;
|
||||
|
||||
/**
|
||||
* 序列数位长
|
||||
* 默认值6,取值范围 [3, 21](要求:序列数位长+机器码位长不超过22)
|
||||
*/
|
||||
byte SeqBitLength = 6;
|
||||
|
||||
/**
|
||||
* 最大序列数(含)
|
||||
* 设置范围 [MinSeqNumber, 2^SeqBitLength-1],默认值0,表示最大序列数取最大值(2^SeqBitLength-1])
|
||||
*/
|
||||
short MaxSeqNumber = 0;
|
||||
|
||||
/**
|
||||
* 最小序列数(含)
|
||||
* 默认值5,取值范围 [5, MaxSeqNumber],每毫秒的前5个序列数对应编号是0-4是保留位,其中1-4是时间回拨相应预留位,0是手工新值预留位
|
||||
*/
|
||||
short MinSeqNumber = 5;
|
||||
|
||||
/**
|
||||
* 最大漂移次数(含)
|
||||
* 默认2000,推荐范围500-10000(与计算能力有关)
|
||||
*/
|
||||
short TopOverCostCount = 2000;
|
||||
|
||||
this() {
|
||||
BaseTime = SysTime(DateTime(2020, 2, 20, 2, 20, 2));
|
||||
}
|
||||
|
||||
this(short workerId) {
|
||||
WorkerId = workerId;
|
||||
BaseTime = SysTime(DateTime(2020, 2, 20, 2, 20, 2));
|
||||
}
|
||||
}
|
||||
52
D/source/yitter/contract/OverCostActionArg.d
Normal file
52
D/source/yitter/contract/OverCostActionArg.d
Normal file
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* 版权属于:yitter(yitter@126.com)
|
||||
* 开源地址:https://gitee.com/yitter/idgenerator
|
||||
*/
|
||||
module yitter.contract.OverCostActionArg;
|
||||
|
||||
/**
|
||||
* Id生成时回调参数
|
||||
*/
|
||||
class OverCostActionArg {
|
||||
|
||||
/**
|
||||
* 事件类型
|
||||
* 1-开始,2-结束,8-漂移
|
||||
*/
|
||||
int ActionType = 0;
|
||||
|
||||
/**
|
||||
* 时间戳
|
||||
*/
|
||||
long TimeTick = 0;
|
||||
|
||||
/**
|
||||
* 机器码
|
||||
*/
|
||||
short WorkerId = 0;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
int OverCostCountInOneTerm = 0;
|
||||
|
||||
/**
|
||||
* 漂移期间生产ID个数
|
||||
*/
|
||||
int GenCountInOneTerm = 0;
|
||||
|
||||
/**
|
||||
* 漂移周期
|
||||
*/
|
||||
int TermIndex = 0;
|
||||
|
||||
this(short workerId, long timeTick, int actionType, int overCostCountInOneTerm,
|
||||
int genCountWhenOverCost, int index) {
|
||||
ActionType = actionType;
|
||||
TimeTick = timeTick;
|
||||
WorkerId = workerId;
|
||||
OverCostCountInOneTerm = overCostCountInOneTerm;
|
||||
GenCountInOneTerm = genCountWhenOverCost;
|
||||
TermIndex = index;
|
||||
}
|
||||
}
|
||||
7
D/source/yitter/contract/package.d
Normal file
7
D/source/yitter/contract/package.d
Normal file
@@ -0,0 +1,7 @@
|
||||
module yitter.contract;
|
||||
|
||||
public import yitter.contract.IdGeneratorException;
|
||||
public import yitter.contract.IdGeneratorOptions;
|
||||
public import yitter.contract.IIdGenerator;
|
||||
public import yitter.contract.ISnowWorker;
|
||||
public import yitter.contract.OverCostActionArg;
|
||||
237
D/source/yitter/core/SnowWorkerM1.d
Normal file
237
D/source/yitter/core/SnowWorkerM1.d
Normal file
@@ -0,0 +1,237 @@
|
||||
/*
|
||||
* 版权属于:yitter(yitter@126.com)
|
||||
* 开源地址:https://gitee.com/yitter/idgenerator
|
||||
*/
|
||||
module yitter.core.SnowWorkerM1;
|
||||
|
||||
import yitter.contract.ISnowWorker;
|
||||
import yitter.contract.IdGeneratorOptions;
|
||||
import yitter.contract.OverCostActionArg;
|
||||
import yitter.contract.IdGeneratorException;
|
||||
|
||||
import std.datetime;
|
||||
|
||||
class SnowWorkerM1 : ISnowWorker {
|
||||
|
||||
/**
|
||||
* 基础时间
|
||||
*/
|
||||
protected SysTime BaseTime;
|
||||
|
||||
/**
|
||||
* 机器码
|
||||
*/
|
||||
protected short WorkerId;
|
||||
|
||||
/**
|
||||
* 机器码位长
|
||||
*/
|
||||
protected byte WorkerIdBitLength;
|
||||
|
||||
/**
|
||||
* 自增序列数位长
|
||||
*/
|
||||
protected byte SeqBitLength;
|
||||
|
||||
/**
|
||||
* 最大序列数(含)
|
||||
*/
|
||||
protected int MaxSeqNumber;
|
||||
|
||||
/**
|
||||
* 最小序列数(含)
|
||||
*/
|
||||
protected short MinSeqNumber;
|
||||
|
||||
/**
|
||||
* 最大漂移次数
|
||||
*/
|
||||
protected int TopOverCostCount;
|
||||
|
||||
protected byte _TimestampShift;
|
||||
// protected __gshared Object _SyncLock; // = new byte[0];
|
||||
|
||||
protected short _CurrentSeqNumber;
|
||||
protected long _LastTimeTick = 0;
|
||||
protected long _TurnBackTimeTick = 0;
|
||||
protected byte _TurnBackIndex = 0;
|
||||
|
||||
protected bool _IsOverCost = false;
|
||||
protected int _OverCostCountInOneTerm = 0;
|
||||
protected int _GenCountInOneTerm = 0;
|
||||
protected int _TermIndex = 0;
|
||||
|
||||
// shared static this() {
|
||||
// _SyncLock = new Object();
|
||||
// }
|
||||
|
||||
this(IdGeneratorOptions options) {
|
||||
BaseTime = options.BaseTime != SysTime.min ? options.BaseTime : SysTime(DateTime(2020, 2, 20, 2, 20, 2));
|
||||
WorkerIdBitLength = options.WorkerIdBitLength == 0 ? 6 : options.WorkerIdBitLength;
|
||||
WorkerId = options.WorkerId;
|
||||
SeqBitLength = options.SeqBitLength == 0 ? 6 : options.SeqBitLength;
|
||||
MaxSeqNumber = options.MaxSeqNumber <= 0 ? (1 << SeqBitLength) - 1 : options.MaxSeqNumber;
|
||||
MinSeqNumber = options.MinSeqNumber;
|
||||
TopOverCostCount = options.TopOverCostCount == 0 ? 2000 : options.TopOverCostCount;
|
||||
_TimestampShift = cast(byte) (WorkerIdBitLength + SeqBitLength);
|
||||
_CurrentSeqNumber = MinSeqNumber;
|
||||
}
|
||||
|
||||
private void DoGenIdAction(OverCostActionArg arg) {
|
||||
|
||||
}
|
||||
|
||||
private void BeginOverCostAction(long useTimeTick) {
|
||||
|
||||
}
|
||||
|
||||
private void EndOverCostAction(long useTimeTick) {
|
||||
if (_TermIndex > 10000) {
|
||||
_TermIndex = 0;
|
||||
}
|
||||
}
|
||||
|
||||
private void BeginTurnBackAction(long useTimeTick) {
|
||||
|
||||
}
|
||||
|
||||
private void EndTurnBackAction(long useTimeTick) {
|
||||
|
||||
}
|
||||
|
||||
private long NextOverCostId() {
|
||||
long currentTimeTick = GetCurrentTimeTick();
|
||||
|
||||
if (currentTimeTick > _LastTimeTick) {
|
||||
EndOverCostAction(currentTimeTick);
|
||||
|
||||
_LastTimeTick = currentTimeTick;
|
||||
_CurrentSeqNumber = MinSeqNumber;
|
||||
_IsOverCost = false;
|
||||
_OverCostCountInOneTerm = 0;
|
||||
_GenCountInOneTerm = 0;
|
||||
|
||||
return CalcId(_LastTimeTick);
|
||||
}
|
||||
|
||||
if (_OverCostCountInOneTerm >= TopOverCostCount) {
|
||||
EndOverCostAction(currentTimeTick);
|
||||
|
||||
_LastTimeTick = GetNextTimeTick();
|
||||
_CurrentSeqNumber = MinSeqNumber;
|
||||
_IsOverCost = false;
|
||||
_OverCostCountInOneTerm = 0;
|
||||
_GenCountInOneTerm = 0;
|
||||
|
||||
return CalcId(_LastTimeTick);
|
||||
}
|
||||
|
||||
if (_CurrentSeqNumber > MaxSeqNumber) {
|
||||
_LastTimeTick++;
|
||||
_CurrentSeqNumber = MinSeqNumber;
|
||||
_IsOverCost = true;
|
||||
_OverCostCountInOneTerm++;
|
||||
_GenCountInOneTerm++;
|
||||
|
||||
return CalcId(_LastTimeTick);
|
||||
}
|
||||
|
||||
_GenCountInOneTerm++;
|
||||
return CalcId(_LastTimeTick);
|
||||
}
|
||||
|
||||
private long NextNormalId() {
|
||||
long currentTimeTick = GetCurrentTimeTick();
|
||||
|
||||
if (currentTimeTick < _LastTimeTick) {
|
||||
if (_TurnBackTimeTick < 1) {
|
||||
_TurnBackTimeTick = _LastTimeTick - 1;
|
||||
_TurnBackIndex++;
|
||||
|
||||
// 每毫秒序列数的前5位是预留位,0用于手工新值,1-4是时间回拨次序
|
||||
// 最多4次回拨(防止回拨重叠)
|
||||
if (_TurnBackIndex > 4) {
|
||||
_TurnBackIndex = 1;
|
||||
}
|
||||
BeginTurnBackAction(_TurnBackTimeTick);
|
||||
}
|
||||
|
||||
// try {
|
||||
// Thread.sleep(1);
|
||||
// } catch (InterruptedException e) {
|
||||
// e.printStackTrace();
|
||||
// }
|
||||
|
||||
return CalcTurnBackId(_TurnBackTimeTick);
|
||||
}
|
||||
|
||||
// 时间追平时,_TurnBackTimeTick清零
|
||||
if (_TurnBackTimeTick > 0) {
|
||||
EndTurnBackAction(_TurnBackTimeTick);
|
||||
_TurnBackTimeTick = 0;
|
||||
}
|
||||
|
||||
if (currentTimeTick > _LastTimeTick) {
|
||||
_LastTimeTick = currentTimeTick;
|
||||
_CurrentSeqNumber = MinSeqNumber;
|
||||
|
||||
return CalcId(_LastTimeTick);
|
||||
}
|
||||
|
||||
if (_CurrentSeqNumber > MaxSeqNumber) {
|
||||
BeginOverCostAction(currentTimeTick);
|
||||
|
||||
_TermIndex++;
|
||||
_LastTimeTick++;
|
||||
_CurrentSeqNumber = MinSeqNumber;
|
||||
_IsOverCost = true;
|
||||
_OverCostCountInOneTerm = 1;
|
||||
_GenCountInOneTerm = 1;
|
||||
|
||||
return CalcId(_LastTimeTick);
|
||||
}
|
||||
|
||||
return CalcId(_LastTimeTick);
|
||||
}
|
||||
|
||||
private long CalcId(long useTimeTick) {
|
||||
long result = ((useTimeTick << _TimestampShift) +
|
||||
(cast(long) WorkerId << SeqBitLength) +
|
||||
cast(int) _CurrentSeqNumber);
|
||||
|
||||
_CurrentSeqNumber++;
|
||||
return result;
|
||||
}
|
||||
|
||||
private long CalcTurnBackId(long useTimeTick) {
|
||||
long result = ((useTimeTick << _TimestampShift) +
|
||||
(cast(long) WorkerId << SeqBitLength) + _TurnBackIndex);
|
||||
|
||||
_TurnBackTimeTick--;
|
||||
return result;
|
||||
}
|
||||
|
||||
protected long GetCurrentTimeTick() {
|
||||
SysTime now = Clock.currTime;
|
||||
Duration dur = Clock.currTime - BaseTime;
|
||||
return dur.total!("msecs");
|
||||
}
|
||||
|
||||
protected long GetNextTimeTick() {
|
||||
long tempTimeTicker = GetCurrentTimeTick();
|
||||
|
||||
while (tempTimeTicker <= _LastTimeTick) {
|
||||
tempTimeTicker = GetCurrentTimeTick();
|
||||
}
|
||||
|
||||
return tempTimeTicker;
|
||||
}
|
||||
|
||||
override
|
||||
long nextId() {
|
||||
synchronized {
|
||||
return _IsOverCost ? NextOverCostId() : NextNormalId();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
50
D/source/yitter/core/SnowWorkerM2.d
Normal file
50
D/source/yitter/core/SnowWorkerM2.d
Normal file
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* 版权属于:yitter(yitter@126.com)
|
||||
* 开源地址:https://gitee.com/yitter/idgenerator
|
||||
*/
|
||||
module yitter.core.SnowWorkerM2;
|
||||
|
||||
import yitter.core.SnowWorkerM1;
|
||||
|
||||
import yitter.contract.IdGeneratorOptions;
|
||||
import yitter.contract.IdGeneratorException;
|
||||
|
||||
import std.format;
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
class SnowWorkerM2 : SnowWorkerM1 {
|
||||
|
||||
this(IdGeneratorOptions options) {
|
||||
super(options);
|
||||
}
|
||||
|
||||
override
|
||||
long nextId() {
|
||||
synchronized {
|
||||
long currentTimeTick = GetCurrentTimeTick();
|
||||
|
||||
if (_LastTimeTick == currentTimeTick) {
|
||||
if (_CurrentSeqNumber++ > MaxSeqNumber) {
|
||||
_CurrentSeqNumber = MinSeqNumber;
|
||||
currentTimeTick = GetNextTimeTick();
|
||||
}
|
||||
} else {
|
||||
_CurrentSeqNumber = MinSeqNumber;
|
||||
}
|
||||
|
||||
if (currentTimeTick < _LastTimeTick) {
|
||||
string msg = format("Time error for %d milliseconds", _LastTimeTick - currentTimeTick);
|
||||
throw new IdGeneratorException(msg);
|
||||
}
|
||||
|
||||
_LastTimeTick = currentTimeTick;
|
||||
long result = ((currentTimeTick << _TimestampShift) + (cast(long) WorkerId << SeqBitLength) + cast(int) _CurrentSeqNumber);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
98
D/source/yitter/idgen/DefaultIdGenerator.d
Normal file
98
D/source/yitter/idgen/DefaultIdGenerator.d
Normal file
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
* 版权属于:yitter(yitter@126.com)
|
||||
* 开源地址:https://gitee.com/yitter/idgenerator
|
||||
*/
|
||||
module yitter.idgen.DefaultIdGenerator;
|
||||
|
||||
import yitter.contract.IIdGenerator;
|
||||
import yitter.contract.ISnowWorker;
|
||||
import yitter.contract.IdGeneratorException;
|
||||
import yitter.contract.IdGeneratorOptions;
|
||||
import yitter.core.SnowWorkerM1;
|
||||
import yitter.core.SnowWorkerM2;
|
||||
|
||||
import core.thread;
|
||||
import core.time;
|
||||
|
||||
import std.conv;
|
||||
import std.datetime;
|
||||
import std.stdio;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
class DefaultIdGenerator : IIdGenerator {
|
||||
|
||||
private __gshared ISnowWorker _SnowWorker = null;
|
||||
|
||||
this(IdGeneratorOptions options) {
|
||||
if (options is null) {
|
||||
throw new IdGeneratorException("options error.");
|
||||
}
|
||||
|
||||
// 1.BaseTime
|
||||
SysTime MinBaseTime = SysTime(DateTime(2020, 2, 20, 2, 20, 2)).add!"years"(-50);
|
||||
if (options.BaseTime < MinBaseTime || options.BaseTime > Clock.currTime) {
|
||||
throw new IdGeneratorException("BaseTime error.");
|
||||
}
|
||||
|
||||
// 2.WorkerIdBitLength
|
||||
if (options.WorkerIdBitLength <= 0) {
|
||||
throw new IdGeneratorException("WorkerIdBitLength error.(range:[1, 21])");
|
||||
}
|
||||
if (options.WorkerIdBitLength + options.SeqBitLength > 22) {
|
||||
throw new IdGeneratorException("error:WorkerIdBitLength + SeqBitLength <= 22");
|
||||
}
|
||||
|
||||
// 3.WorkerId
|
||||
int maxWorkerIdNumber = (1 << options.WorkerIdBitLength) - 1;
|
||||
if (maxWorkerIdNumber == 0) {
|
||||
maxWorkerIdNumber = 63;
|
||||
}
|
||||
if (options.WorkerId < 0 || options.WorkerId > maxWorkerIdNumber) {
|
||||
string msg = "WorkerId error. (range:[0, " ~ to!string((maxWorkerIdNumber > 0 ? maxWorkerIdNumber : 63)) ~ "]";
|
||||
throw new IdGeneratorException(msg);
|
||||
}
|
||||
|
||||
// 4.SeqBitLength
|
||||
if (options.SeqBitLength < 2 || options.SeqBitLength > 21) {
|
||||
throw new IdGeneratorException("SeqBitLength error. (range:[2, 21])");
|
||||
}
|
||||
|
||||
// 5.MaxSeqNumber
|
||||
int maxSeqNumber = (1 << options.SeqBitLength) - 1;
|
||||
if (maxSeqNumber == 0) {
|
||||
maxSeqNumber = 63;
|
||||
}
|
||||
if (options.MaxSeqNumber < 0 || options.MaxSeqNumber > maxSeqNumber) {
|
||||
throw new IdGeneratorException("MaxSeqNumber error. (range:[1, " ~ maxSeqNumber.to!string() ~ "]");
|
||||
}
|
||||
|
||||
// 6.MinSeqNumber
|
||||
if (options.MinSeqNumber < 5 || options.MinSeqNumber > maxSeqNumber) {
|
||||
throw new IdGeneratorException("MinSeqNumber error. (range:[5, " ~ maxSeqNumber.to!string() ~ "]");
|
||||
}
|
||||
|
||||
switch (options.Method) {
|
||||
case 2:
|
||||
_SnowWorker = new SnowWorkerM2(options);
|
||||
break;
|
||||
case 1:
|
||||
default:
|
||||
_SnowWorker = new SnowWorkerM1(options);
|
||||
break;
|
||||
}
|
||||
|
||||
if (options.Method == 1) {
|
||||
try {
|
||||
Thread.sleep(500.msecs);
|
||||
} catch (Exception e) {
|
||||
writeln(e.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
long newLong() {
|
||||
return _SnowWorker.nextId();
|
||||
}
|
||||
}
|
||||
43
D/source/yitter/idgen/YitIdHelper.d
Normal file
43
D/source/yitter/idgen/YitIdHelper.d
Normal file
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* 版权属于:yitter(yitter@126.com)
|
||||
* 开源地址:https://gitee.com/yitter/idgenerator
|
||||
*/
|
||||
module yitter.idgen.YitIdHelper;
|
||||
|
||||
import yitter.idgen.DefaultIdGenerator;
|
||||
|
||||
import yitter.contract.IIdGenerator;
|
||||
import yitter.contract.IdGeneratorException;
|
||||
import yitter.contract.IdGeneratorOptions;
|
||||
|
||||
import std.concurrency : initOnce;
|
||||
|
||||
/**
|
||||
* 这是一个调用的例子,默认情况下,单机集成者可以直接使用 nextId()。
|
||||
*/
|
||||
class YitIdHelper {
|
||||
|
||||
private __gshared IIdGenerator idGenInstance = null;
|
||||
|
||||
static IIdGenerator getIdGenInstance() {
|
||||
return initOnce!idGenInstance(new DefaultIdGenerator(new IdGeneratorOptions(1)));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置参数,建议程序初始化时执行一次
|
||||
*/
|
||||
static void setIdGenerator(IdGeneratorOptions options) {
|
||||
idGenInstance = new DefaultIdGenerator(options);
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成新的Id
|
||||
* 调用本方法前,请确保调用了 SetIdGenerator 方法做初始化。
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
static long nextId() {
|
||||
return getIdGenInstance().newLong();
|
||||
}
|
||||
}
|
||||
6
D/source/yitter/package.d
Normal file
6
D/source/yitter/package.d
Normal file
@@ -0,0 +1,6 @@
|
||||
module yitter;
|
||||
|
||||
public import yitter.contract;
|
||||
|
||||
public import yitter.idgen.DefaultIdGenerator;
|
||||
public import yitter.idgen.YitIdHelper;
|
||||
14
D/test/dub.json
Normal file
14
D/test/dub.json
Normal file
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"authors": [
|
||||
"yitter",
|
||||
"HuntLabs"
|
||||
],
|
||||
"description": "A minimal D application.",
|
||||
"license": "proprietary",
|
||||
"name": "test",
|
||||
"dependencies": {
|
||||
"yitterd" : {
|
||||
"path": "../"
|
||||
}
|
||||
}
|
||||
}
|
||||
38
D/test/source/GenTest.d
Normal file
38
D/test/source/GenTest.d
Normal file
@@ -0,0 +1,38 @@
|
||||
module GenTest;
|
||||
|
||||
import yitter.contract.IIdGenerator;
|
||||
|
||||
import std.conv;
|
||||
import std.datetime;
|
||||
import std.stdio;
|
||||
|
||||
|
||||
class GenTest {
|
||||
|
||||
private IIdGenerator IdGen;
|
||||
private int GenIdCount;
|
||||
private int WorkerId;
|
||||
|
||||
this(IIdGenerator idGen, int genIdCount, int workerId) {
|
||||
GenIdCount = genIdCount;
|
||||
IdGen = idGen;
|
||||
WorkerId = workerId;
|
||||
}
|
||||
|
||||
void GenStart() {
|
||||
MonoTime start = MonoTime.currTime();
|
||||
long id = 0;
|
||||
|
||||
for (int i = 0; i < GenIdCount; i++) {
|
||||
id = IdGen.newLong();
|
||||
}
|
||||
|
||||
MonoTime end = MonoTime.currTime();
|
||||
Duration dur = end - start;
|
||||
|
||||
// writeln(id);
|
||||
writeln("++++++++++++++++++++++++++++++++++++++++WorkerId: "
|
||||
~ WorkerId.to!string() ~ ", total: " ~ dur.total!("msecs").to!string() ~ " ms");
|
||||
|
||||
}
|
||||
}
|
||||
52
D/test/source/app.d
Normal file
52
D/test/source/app.d
Normal file
@@ -0,0 +1,52 @@
|
||||
import std.stdio;
|
||||
|
||||
import yitter;
|
||||
import GenTest;
|
||||
|
||||
import core.thread;
|
||||
|
||||
import std.conv;
|
||||
import std.datetime;
|
||||
import std.stdio;
|
||||
|
||||
/**
|
||||
* 测试结果:
|
||||
* (1):1W并发,方法 1只要 1ms.而方法 2 要 180ms。
|
||||
* (2):5W并发,方法 1只要 3ms.而方法 2 要 900ms。
|
||||
* [不同CPU可能结果有差异,但相对大小不变]
|
||||
* 默认配置下,最佳性能是5W/s-8W/s
|
||||
*/
|
||||
enum int genIdCount = 50000;
|
||||
|
||||
//1-漂移算法,2-传统算法
|
||||
enum short method = 1;
|
||||
|
||||
void main()
|
||||
{
|
||||
|
||||
IdGeneratorOptions options = new IdGeneratorOptions();
|
||||
|
||||
options.Method = method;
|
||||
options.BaseTime = SysTime(DateTime(2020, 2, 20, 21, 51, 33));
|
||||
options.WorkerId = 1;
|
||||
|
||||
IIdGenerator idGen = new DefaultIdGenerator(options);
|
||||
GenTest.GenTest genTest = new GenTest.GenTest(idGen, genIdCount, options.WorkerId);
|
||||
|
||||
// 首先测试一下 IdHelper 方法,获取单个Id
|
||||
YitIdHelper.setIdGenerator(options);
|
||||
long newId = YitIdHelper.nextId();
|
||||
writeln("=====================================");
|
||||
writeln("这是用方法 " ~ method.to!string() ~ " 生成的 Id:" ~ newId.to!string());
|
||||
|
||||
// 然后循环测试一下,看看并发请求时的耗时情况
|
||||
try {
|
||||
while (true) {
|
||||
genTest.GenStart();
|
||||
// Thread.sleep(200.msecs); // 每隔1秒执行一次GenStart
|
||||
// writeln("Hello World! D");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
writeln(e.toString());
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user