Browse Source

!6 D语言移植

* Porting to D
* The pthread needed.
tags/v1.1.0
BitWorld yitter 3 years ago
parent
commit
a82d9cb063
18 changed files with 768 additions and 3 deletions
  1. +7
    -0
      .gitignore
  2. +4
    -3
      C/source/CMakeLists.txt
  3. +32
    -0
      D/README.md
  4. +9
    -0
      D/dub.json
  5. +9
    -0
      D/source/yitter/contract/IIdGenerator.d
  6. +9
    -0
      D/source/yitter/contract/ISnowWorker.d
  7. +29
    -0
      D/source/yitter/contract/IdGeneratorException.d
  8. +72
    -0
      D/source/yitter/contract/IdGeneratorOptions.d
  9. +52
    -0
      D/source/yitter/contract/OverCostActionArg.d
  10. +7
    -0
      D/source/yitter/contract/package.d
  11. +237
    -0
      D/source/yitter/core/SnowWorkerM1.d
  12. +50
    -0
      D/source/yitter/core/SnowWorkerM2.d
  13. +98
    -0
      D/source/yitter/idgen/DefaultIdGenerator.d
  14. +43
    -0
      D/source/yitter/idgen/YitIdHelper.d
  15. +6
    -0
      D/source/yitter/package.d
  16. +14
    -0
      D/test/dub.json
  17. +38
    -0
      D/test/source/GenTest.d
  18. +52
    -0
      D/test/source/app.d

+ 7
- 0
.gitignore View File

@@ -257,3 +257,10 @@ target/


# macOS # macOS
.DS_Store .DS_Store
D/test/test
D/libyitterd.a
D/dub.*.json
*/.dub/*
*/test/.dub/*
C/source/build/*
D/test/dub.*.json

+ 4
- 3
C/source/CMakeLists.txt View File

@@ -1,4 +1,4 @@
cmake_minimum_required(VERSION 3.17)
cmake_minimum_required(VERSION 3.13)
project(YitIdGen) project(YitIdGen)
set(CMAKE_C_STANDARD 11) set(CMAKE_C_STANDARD 11)


@@ -8,6 +8,7 @@ set(CMAKE_C_STANDARD 11)
aux_source_directory(. DIR_SRCS) aux_source_directory(. DIR_SRCS)
add_subdirectory(idgen) add_subdirectory(idgen)



#编译动态库 #编译动态库
#set(LIB_SRC YitIdHelper.h YitIdHelper.c) #set(LIB_SRC YitIdHelper.h YitIdHelper.c)
#add_library(YitIdGenLib SHARED ${LIB_SRC}) #add_library(YitIdGenLib SHARED ${LIB_SRC})
@@ -21,7 +22,7 @@ add_subdirectory(idgen)
set(LIB_SRC YitIdHelper.h YitIdHelper.c) set(LIB_SRC YitIdHelper.h YitIdHelper.c)
add_library(YitIdHelper ${LIB_SRC}) add_library(YitIdHelper ${LIB_SRC})
add_executable(YitIdGen main.c) 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
- 0
D/README.md View 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
- 0
D/dub.json View File

@@ -0,0 +1,9 @@
{
"authors": [
"yitter",
"HuntLabs"
],
"description": "A minimal D application.",
"license": "proprietary",
"name": "yitterd"
}

+ 9
- 0
D/source/yitter/contract/IIdGenerator.d View File

@@ -0,0 +1,9 @@
/*
* 版权属于:yitter(yitter@126.com)
* 开源地址:https://gitee.com/yitter/idgenerator
*/
module yitter.contract.IIdGenerator;
interface IIdGenerator {
long newLong();
}

+ 9
- 0
D/source/yitter/contract/ISnowWorker.d View File

@@ -0,0 +1,9 @@
/*
* 版权属于:yitter(yitter@126.com)
* 开源地址:https://gitee.com/yitter/idgenerator
*/
module yitter.contract.ISnowWorker;
interface ISnowWorker {
long nextId();
}

+ 29
- 0
D/source/yitter/contract/IdGeneratorException.d View 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
- 0
D/source/yitter/contract/IdGeneratorOptions.d View 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
- 0
D/source/yitter/contract/OverCostActionArg.d View 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
- 0
D/source/yitter/contract/package.d View 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
- 0
D/source/yitter/core/SnowWorkerM1.d View 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
- 0
D/source/yitter/core/SnowWorkerM2.d View 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
- 0
D/source/yitter/idgen/DefaultIdGenerator.d View 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
- 0
D/source/yitter/idgen/YitIdHelper.d View 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
- 0
D/source/yitter/package.d View File

@@ -0,0 +1,6 @@
module yitter;

public import yitter.contract;

public import yitter.idgen.DefaultIdGenerator;
public import yitter.idgen.YitIdHelper;

+ 14
- 0
D/test/dub.json View File

@@ -0,0 +1,14 @@
{
"authors": [
"yitter",
"HuntLabs"
],
"description": "A minimal D application.",
"license": "proprietary",
"name": "test",
"dependencies": {
"yitterd" : {
"path": "../"
}
}
}

+ 38
- 0
D/test/source/GenTest.d View 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
- 0
D/test/source/app.d View 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());
}
}

Loading…
Cancel
Save