From f57d9f1de616d8d55f5366ae1bf6c576afd2dbd4 Mon Sep 17 00:00:00 2001 From: yitter Date: Mon, 17 Oct 2022 11:34:58 +0800 Subject: [PATCH] auto commit --- Delphi/README.md | 70 ++ Delphi/source/.gitignore | 5 + Delphi/source/BakClear.bat | 3 + Delphi/source/Contract/uIIdGenerator.pas | 16 + Delphi/source/Contract/uISnowWorker.pas | 13 + Delphi/source/Contract/uIdGeneratorOptions.pas | 97 +++ Delphi/source/Contract/uTOverCostActionArg.pas | 61 ++ Delphi/source/Core/uSnowWorkerM1.pas | 404 ++++++++++ Delphi/source/Core/uSnowWorkerM2.pas | 75 ++ Delphi/source/Core/uSnowWorkerM3.pas | 91 +++ Delphi/source/IdGenTest.dpr | 25 + Delphi/source/IdGenTest.dproj | 987 +++++++++++++++++++++++++ Delphi/source/IdGenTest.res | Bin 0 -> 59520 bytes Delphi/source/uDefaultIdGenerator.pas | 137 ++++ Delphi/source/uTest.dfm | 80 ++ Delphi/source/uTest.pas | 197 +++++ Delphi/source/uYitIdHelper.pas | 51 ++ README.md | 5 +- 18 files changed, 2315 insertions(+), 2 deletions(-) create mode 100644 Delphi/README.md create mode 100644 Delphi/source/.gitignore create mode 100644 Delphi/source/BakClear.bat create mode 100644 Delphi/source/Contract/uIIdGenerator.pas create mode 100644 Delphi/source/Contract/uISnowWorker.pas create mode 100644 Delphi/source/Contract/uIdGeneratorOptions.pas create mode 100644 Delphi/source/Contract/uTOverCostActionArg.pas create mode 100644 Delphi/source/Core/uSnowWorkerM1.pas create mode 100644 Delphi/source/Core/uSnowWorkerM2.pas create mode 100644 Delphi/source/Core/uSnowWorkerM3.pas create mode 100644 Delphi/source/IdGenTest.dpr create mode 100644 Delphi/source/IdGenTest.dproj create mode 100644 Delphi/source/IdGenTest.res create mode 100644 Delphi/source/uDefaultIdGenerator.pas create mode 100644 Delphi/source/uTest.dfm create mode 100644 Delphi/source/uTest.pas create mode 100644 Delphi/source/uYitIdHelper.pas diff --git a/Delphi/README.md b/Delphi/README.md new file mode 100644 index 0000000..20eecc4 --- /dev/null +++ b/Delphi/README.md @@ -0,0 +1,70 @@ +# ❄ idgenerator-Delphi + +## 编译环境、运行环境 + +Delphi XE10.3.3 + +## 调用示例(Delphi) + +第1步,**全局**初始化(创建只执行一次): + +```objectpascal +// 添加引用 +uses uIdGeneratorOptions, uIIdGenerator, uDefaultIdGenerator, uYitIdHelper; + +// 声明IdGeneratorOptions、YitIdHelper对象为全局变量 +var + IdGeneratorOption: TIdGeneratorOptions; + YitIdHelper: TYitIdHelper; + +// 创建并配置雪花算法参数: +begin + IdGeneratorOption := TIdGeneratorOptions.Create; + // 参数参考IdGeneratorOptions定义。 + with IdGeneratorOptiondo + begin + //以下全部为默认参数 + Method := 1; + // BaseTime := DateTime.Now.AddYears(-10); + WorkerId := 1; + + WorkerIdBitLength := 6; + SeqBitLength := 6; + + MaxSeqNumber := 0; + MinSeqNumber := 5; + + TopOverCostCount := 2000; + + DataCenterId := 0; + DataCenterIdBitLength := 0; + + TimestampType := 0; + end; + + YitIdHelper := TYitIdHelper.Create; + // 保存参数(务必调用,否则参数设置不生效): + YitIdHelper.SetIdGenerator(options); + + // 以上过程只需全局一次,且应在生成Id之前完成。 +end; +``` + +第2步,生成ID: + +```objectpascal +// 初始化后,在任何需要生成Id的地方,调用以下方法: +var Id: Int64 := YitIdHelper.NextId(); +``` + +第3步,释放内存(销毁只执行一次): + +```objectpascal +YitIdHelper.Free; +IdGeneratorOption.Free; +``` + +## 代码贡献者 +塵封追憶(Delphi-asdf, 82257695) + + diff --git a/Delphi/source/.gitignore b/Delphi/source/.gitignore new file mode 100644 index 0000000..63788ae --- /dev/null +++ b/Delphi/source/.gitignore @@ -0,0 +1,5 @@ +Win32/ +*.exe +*.dproj.local +*.identcache +__* diff --git a/Delphi/source/BakClear.bat b/Delphi/source/BakClear.bat new file mode 100644 index 0000000..2e652cb --- /dev/null +++ b/Delphi/source/BakClear.bat @@ -0,0 +1,3 @@ +DEL /S *.~* +DEL /S *.DCU +DEL /S *.DDP \ No newline at end of file diff --git a/Delphi/source/Contract/uIIdGenerator.pas b/Delphi/source/Contract/uIIdGenerator.pas new file mode 100644 index 0000000..aa76c69 --- /dev/null +++ b/Delphi/source/Contract/uIIdGenerator.pas @@ -0,0 +1,16 @@ +unit uIIdGenerator; + +interface + +type + IIdGenerator = interface + ['{C4E773E0-6E3E-410D-9F01-0826BA57BFF0}'] + /// + /// µInt64Id + /// + function NewLong(): Int64; + end; + +implementation + +end. diff --git a/Delphi/source/Contract/uISnowWorker.pas b/Delphi/source/Contract/uISnowWorker.pas new file mode 100644 index 0000000..66d4b5a --- /dev/null +++ b/Delphi/source/Contract/uISnowWorker.pas @@ -0,0 +1,13 @@ +unit uISnowWorker; + +interface + +type + ISnowWorker = interface + ['{AB5DCE35-5745-417F-9217-9094CA651A8C}'] + function NextId(): Int64; + end; + +implementation + +end. diff --git a/Delphi/source/Contract/uIdGeneratorOptions.pas b/Delphi/source/Contract/uIdGeneratorOptions.pas new file mode 100644 index 0000000..901c04f --- /dev/null +++ b/Delphi/source/Contract/uIdGeneratorOptions.pas @@ -0,0 +1,97 @@ +unit uIdGeneratorOptions; + +interface + +uses + System.DateUtils, System.SysUtils; + +type + TIdGeneratorOptions = class + private + FMethod: SmallInt; + // FBaseTime: TDateTime; + FBaseTime: Int64; + FWorkerId: Word; + FWorkerIdBitLength: Byte; + FSeqBitLength: Byte; + FMaxSeqNumber: Integer; + FMinSeqNumber: Word; + FTopOverCostCount: Integer; + FDataCenterId: Cardinal; + FDataCenterIdBitLength: Byte; + FTimestampType: Byte; + public + /// + /// ѩ㷽 + /// 1-Ư㷨|2-ͳ㷨Ĭ1 + /// + property Method: SmallInt read FMethod write FMethod default 1; + /// + /// ʱ䣨UTCʽ + /// ܳǰϵͳʱ + /// + // property BaseTime: TDateTime read FBaseTime write FBaseTime; + property BaseTime: Int64 read FBaseTime write FBaseTime; + /// + /// + /// ⲿ趨ֵ 2^WorkerIdBitLength-1 + /// + property WorkerId: Word read FWorkerId write FWorkerId default 0; + /// + /// λ + /// Ĭֵ6ȡֵΧ [1, 15]Ҫλ+λ22 + /// + property WorkerIdBitLength: Byte read FWorkerIdBitLength write FWorkerIdBitLength default 6; // 10; + /// + /// λ + /// Ĭֵ6ȡֵΧ [3, 21]Ҫλ+λ22 + /// + property SeqBitLength: Byte read FSeqBitLength write FSeqBitLength default 6; // 10; + /// + /// + /// ÷Χ [MinSeqNumber, 2^SeqBitLength-1]Ĭֵ0ʾȡֵ2^SeqBitLength-1] + /// + property MaxSeqNumber: Integer read FMaxSeqNumber write FMaxSeqNumber default 0; + /// + /// С + /// Ĭֵ5ȡֵΧ [5, MaxSeqNumber]ÿǰ5Ӧ0-4DZλ1-4ʱزӦԤλ0ֵֹԤλ + /// + property MinSeqNumber: Word read FMinSeqNumber write FMinSeqNumber default 5; + /// + /// Ưƴ + /// Ĭ2000ƼΧ500-10000йأ + /// + property TopOverCostCount: Integer read FTopOverCostCount write FTopOverCostCount default 2000; + /// + /// IDĬ0 + /// + property DataCenterId: Cardinal read FDataCenterId write FDataCenterId default 0; + /// + /// IDȣĬ0 + /// + property DataCenterIdBitLength: Byte read FDataCenterIdBitLength write FDataCenterIdBitLength default 0; + /// + /// ʱͣ0-룬1-룩Ĭ0 + /// + property TimestampType: Byte read FTimestampType write FTimestampType default 0; + + constructor Create(); overload; + constructor Create(WorkerId: Word); overload; + end; + +implementation + +{ TIdGeneratorOptions } + +constructor TIdGeneratorOptions.Create(WorkerId: Word); +begin + FBaseTime := 1582136402000; // EncodeDateTime(2020, 2, 20, 2, 20, 2, 20); + FWorkerId := WorkerId; +end; + +constructor TIdGeneratorOptions.Create(); +begin + FBaseTime := 1582136402000; // EncodeDateTime(2020, 2, 20, 2, 20, 2, 20); +end; + +end. diff --git a/Delphi/source/Contract/uTOverCostActionArg.pas b/Delphi/source/Contract/uTOverCostActionArg.pas new file mode 100644 index 0000000..d21ba2c --- /dev/null +++ b/Delphi/source/Contract/uTOverCostActionArg.pas @@ -0,0 +1,61 @@ +unit uTOverCostActionArg; + +interface + +type + TOverCostActionArg = class + private + FActionType: Integer; + FTimeTick: Int64; + FWorkerId: Word; + FOverCostCountInOneTerm: Integer; + FGenCountInOneTerm: Integer; + FTermIndex: Integer; + public + /// + /// ¼ + /// 1-ʼ2-8-Ư + /// + property ActionType: Integer read FActionType write FActionType default 0; + /// + /// ʱ + /// + property TimeTick: Int64 read FTimeTick write FTimeTick; + /// + /// + /// + property WorkerId: Word read FWorkerId write FWorkerId; + /// + /// ƯƼ + /// + property OverCostCountInOneTerm: Integer read FOverCostCountInOneTerm write FOverCostCountInOneTerm default 0; + /// + /// ƯڼID + /// + property GenCountInOneTerm: Integer read FGenCountInOneTerm write FGenCountInOneTerm default 0; + /// + /// Ư + /// + property TermIndex: Integer read FTermIndex write FTermIndex default 0; + + constructor Create(const WorkerId: Word; const TimeTick: Int64; const ActionType: Integer = 0; + const OverCostCountInOneTerm: Integer = 0; const GenCountWhenOverCost: Integer = 0; + const Index: Integer = 0); overload; + end; + +implementation + +{ TOverCostActionArg } + +constructor TOverCostActionArg.Create(const WorkerId: Word; const TimeTick: Int64; const ActionType: Integer; + const OverCostCountInOneTerm: Integer; const GenCountWhenOverCost: Integer; const Index: Integer); +begin + FWorkerId := WorkerId; + FTimeTick := TimeTick; + FActionType := ActionType; + FOverCostCountInOneTerm := OverCostCountInOneTerm; + FGenCountInOneTerm := GenCountWhenOverCost; + FTermIndex := Index; +end; + +end. diff --git a/Delphi/source/Core/uSnowWorkerM1.pas b/Delphi/source/Core/uSnowWorkerM1.pas new file mode 100644 index 0000000..d2b9ba0 --- /dev/null +++ b/Delphi/source/Core/uSnowWorkerM1.pas @@ -0,0 +1,404 @@ +unit uSnowWorkerM1; + +interface + +uses + uISnowWorker, uIdGeneratorOptions, System.SyncObjs, uTOverCostActionArg, System.DateUtils, System.SysUtils; + +/// +/// ѩƯ㷨 +/// +type + TSnowWorkerM1 = class(TInterfacedObject, ISnowWorker) + private + // private static long _StartTimeTick = 0; + // private static long _BaseTimeTick = 0; + protected + SyncLock: TCriticalSection; + protected + // FBaseTime: TDateTime; + FBaseTime: Int64; + FWorkerId: Word; + FWorkerIdBitLength: Byte; + FSeqBitLength: Byte; + FMaxSeqNumber: Integer; + FMinSeqNumber: Word; + FTopOverCostCount: Integer; + // + FTimestampShift: Byte; + FCurrentSeqNumber: Word; + FLastTimeTick: Int64; + FTurnBackTimeTick: Int64; + FTurnBackIndex: Byte; + FIsOverCost: Boolean; + FOverCostCountInOneTerm: Integer; + // + FGenCountInOneTerm: Integer; + FTermIndex: Integer; + protected + /// + /// ʱ + /// + // property BaseTime: TDateTime read FBaseTime write FBaseTime; + property BaseTime: Int64 read FBaseTime; + /// + /// + /// + property WorkerId: Word read FWorkerId default 0; + /// + /// λ + /// + property WorkerIdBitLength: Byte read FWorkerIdBitLength default 0; + /// + /// λ + /// + property SeqBitLength: Byte read FSeqBitLength default 0; + /// + /// + /// + property MaxSeqNumber: Integer read FMaxSeqNumber default 0; + /// + /// С + /// + property MinSeqNumber: Word read FMinSeqNumber default 0; + /// + /// Ưƴ + /// + property TopOverCostCount: Integer read FTopOverCostCount write FTopOverCostCount default 0; + + // + property TimestampShift: Byte read FTimestampShift write FTimestampShift default 0; + + // + property CurrentSeqNumber: Word read FCurrentSeqNumber write FCurrentSeqNumber; + property LastTimeTick: Int64 read FLastTimeTick write FLastTimeTick default 0; // -1L + property TurnBackTimeTick: Int64 read FTurnBackTimeTick write FTurnBackTimeTick default 0; // -1L; + property TurnBackIndex: Byte read FTurnBackIndex write FTurnBackIndex default 0; + property IsOverCost: Boolean read FIsOverCost write FIsOverCost default False; + property OverCostCountInOneTerm: Integer read FOverCostCountInOneTerm write FOverCostCountInOneTerm default 0; +{$IFDEF DEBUG} + property GenCountInOneTerm: Integer read FGenCountInOneTerm write FGenCountInOneTerm default 0; + property TermIndex: Integer read FTermIndex write FTermIndex default 0; +{$ENDIF} + protected +{$IFDEF DEBUG} + procedure DoGenIdAction(arg: TOverCostActionArg); + procedure BeginOverCostAction(UseTimeTick: Int64); + procedure EndOverCostAction(UseTimeTick: Int64); + procedure BeginTurnBackAction(UseTimeTick: Int64); + procedure EndTurnBackAction(UseTimeTick: Int64); +{$ENDIF} + // + function GetSecondTimeStamp(): Int64; + function GetMillisecondTimeStamp(): Int64; + // + function CalcId(UseTimeTick: Int64): Int64; virtual; + function CalcTurnBackId(UseTimeTick: Int64): Int64; virtual; + function NextOverCostId(): Int64; + function GetCurrentTimeTick(): Int64; virtual; + function GetNextTimeTick(): Int64; + public + // Action GenAction { get; set; } + function NextId(): Int64; + function NextNormalId(): Int64; + constructor Create(options: TIdGeneratorOptions); overload; + destructor Destroy(); override; + end; + +implementation + +{ TSnowWorkerM1 } + +function TSnowWorkerM1.GetSecondTimeStamp(): Int64; +var + ST: TDateTime; +begin + ST := EncodeDateTime(1970, 1, 1, 0, 0, 0, 0); + Result := MilliSecondsBetween(Now(), ST) - 28800; // 8*60*60; +end; + +function TSnowWorkerM1.GetMillisecondTimeStamp(): Int64; +var + ST: TDateTime; +begin + ST := EncodeDateTime(1970, 1, 1, 0, 0, 0, 0); + Result := MilliSecondsBetween(Now(), ST) - 28800000; // 8*60*60*1000; +end; + +constructor TSnowWorkerM1.Create(options: TIdGeneratorOptions); +begin + SyncLock := TCriticalSection.Create; + // 1.BaseTime + if (options.BaseTime <> 0) then + FBaseTime := options.BaseTime; + + // 2.WorkerIdBitLength + if (options.WorkerIdBitLength <> 0) then + begin + FWorkerIdBitLength := 6; + end + else + begin + FWorkerIdBitLength := options.WorkerIdBitLength; + end; + + // 3.WorkerId + FWorkerId := options.WorkerId; + + // 4.SeqBitLength + if (options.SeqBitLength = 0) then + begin + FSeqBitLength := 6; + end + else + begin + FSeqBitLength := options.SeqBitLength; + end; + + // 5.MaxSeqNumber + if (MaxSeqNumber = 0) then + begin + FMaxSeqNumber := (1 shl SeqBitLength) - 1; + end + else + begin + FMaxSeqNumber := options.MaxSeqNumber; + end; + + // 6.MinSeqNumber + FMinSeqNumber := options.MinSeqNumber; + + // 7.Others + FTopOverCostCount := options.TopOverCostCount; + // if (TopOverCostCount = 0) then + // begin + // FTopOverCostCount := 2000; + // end; + + FTimestampShift := Byte(WorkerIdBitLength + SeqBitLength); + FCurrentSeqNumber := options.MinSeqNumber; + + // FBaseTimeTick = BaseTime.Ticks; + // FStartTimeTick = (long)(DateTime.UtcNow.Subtract(BaseTime).TotalMilliseconds) - Environment.TickCount; +end; + +destructor TSnowWorkerM1.Destroy(); +begin + SyncLock.Free; + + inherited; +end; + +{$IFDEF DEBUG} + +procedure TSnowWorkerM1.DoGenIdAction(arg: TOverCostActionArg); +begin + // //return; + // Task.Run(() => + // { + // GenAction(arg); + // }); +end; + +procedure TSnowWorkerM1.BeginOverCostAction(UseTimeTick: Int64); +begin + +end; + +procedure TSnowWorkerM1.EndOverCostAction(UseTimeTick: Int64); +begin + +end; + +procedure TSnowWorkerM1.BeginTurnBackAction(UseTimeTick: Int64); +begin + +end; + +procedure TSnowWorkerM1.EndTurnBackAction(UseTimeTick: Int64); +begin + +end; +{$ENDIF} + +function TSnowWorkerM1.NextOverCostId(): Int64; +var + CurrentTimeTick: Int64; +begin + CurrentTimeTick := GetCurrentTimeTick(); + + if (CurrentTimeTick > FLastTimeTick) then + begin +{$IFDEF DEBUG} + EndOverCostAction(CurrentTimeTick); + FGenCountInOneTerm := 0; +{$ENDIF} + FLastTimeTick := CurrentTimeTick; + FCurrentSeqNumber := FMinSeqNumber; + FIsOverCost := False; + FOverCostCountInOneTerm := 0; + + Result := CalcId(FLastTimeTick); + Exit; + end; + + if (FOverCostCountInOneTerm >= FTopOverCostCount) then + begin +{$IFDEF DEBUG} + EndOverCostAction(CurrentTimeTick); + FGenCountInOneTerm := 0; +{$ENDIF} + // TODO: Ưֹȴʱʱʱزϳ˴ܵȴϳʱ䡣 + // ŻΪƯֹʱʱزӦ߼ʵͣݲ + FLastTimeTick := GetNextTimeTick(); + FCurrentSeqNumber := FMinSeqNumber; + FIsOverCost := False; + FOverCostCountInOneTerm := 0; + + Result := CalcId(FLastTimeTick); + Exit; + end; + + if (FCurrentSeqNumber > FMaxSeqNumber) then + begin +{$IFDEF DEBUG} + Inc(FGenCountInOneTerm); +{$ENDIF} + Inc(FLastTimeTick); + FCurrentSeqNumber := FMinSeqNumber; + FIsOverCost := True; + Inc(FOverCostCountInOneTerm); + + Result := CalcId(FLastTimeTick); + Exit; + end; + +{$IFDEF DEBUG} + Inc(FGenCountInOneTerm); +{$ENDIF} + Result := CalcId(FLastTimeTick); +end; + +function TSnowWorkerM1.NextNormalId: Int64; +var + CurrentTimeTick: Int64; +begin + CurrentTimeTick := GetCurrentTimeTick(); + + if (CurrentTimeTick < FLastTimeTick) then + begin + if (FTurnBackTimeTick < 1) then + begin + FTurnBackTimeTick := FLastTimeTick - 1; + + Inc(FTurnBackIndex); + // ÿǰ5λԤλ0ֵֹ1-4ʱز + // ֧4λز򣨱زصIDظ޴λزѭʹã + if (FTurnBackIndex > 4) then + begin + FTurnBackIndex := 1; + end; + +{$IFDEF DEBUG} + BeginTurnBackAction(FTurnBackTimeTick); +{$ENDIF} + end; + + // Sleep(1); + Result := CalcTurnBackId(FTurnBackTimeTick); + Exit; + end; + + // ʱ׷ƽʱ_TurnBackTimeTick + if (FTurnBackTimeTick > 0) then + begin +{$IFDEF DEBUG} + EndTurnBackAction(FTurnBackTimeTick); +{$ENDIF} + FTurnBackTimeTick := 0; + end; + + if (CurrentTimeTick > FLastTimeTick) then + begin + FLastTimeTick := CurrentTimeTick; + FCurrentSeqNumber := FMinSeqNumber; + + Result := CalcId(FLastTimeTick); + Exit; + end; + + if (FCurrentSeqNumber > FMaxSeqNumber) then + begin +{$IFDEF DEBUG} + BeginOverCostAction(CurrentTimeTick); + Inc(FTermIndex); + FGenCountInOneTerm := 1; +{$ENDIF} + FOverCostCountInOneTerm := 1; + Inc(FLastTimeTick); + FCurrentSeqNumber := FMinSeqNumber; + FIsOverCost := True; + + Result := CalcId(FLastTimeTick); + Exit; + end; + + Result := CalcId(FLastTimeTick); +end; + +function TSnowWorkerM1.CalcId(UseTimeTick: Int64): Int64; +begin + Result := ((UseTimeTick shl FTimestampShift) + (Int64(FWorkerId) shl FSeqBitLength) + Cardinal(FCurrentSeqNumber)); + + Inc(FCurrentSeqNumber); +end; + +function TSnowWorkerM1.CalcTurnBackId(UseTimeTick: Int64): Int64; +begin + Result := ((UseTimeTick shl FTimestampShift) + (Int64(FWorkerId) shl FSeqBitLength) + FTurnBackIndex); + + Dec(FTurnBackTimeTick); +end; + +function TSnowWorkerM1.GetCurrentTimeTick(): Int64; +var + Millis: Int64; +begin + // Millis := DateTimeToUnix(Now(), False); + Millis := GetMillisecondTimeStamp(); + Result := Millis - FBaseTime; +end; + +function TSnowWorkerM1.GetNextTimeTick(): Int64; +var + TempTimeTicker: Int64; +begin + TempTimeTicker := GetCurrentTimeTick(); + while (TempTimeTicker <= FLastTimeTick) do + begin + // Sleep(1); + TSpinWait.SpinUntil( + function(): Boolean + begin + Result := False; + end, 1); + TempTimeTicker := GetCurrentTimeTick(); + end; + + Result := TempTimeTicker; +end; + +function TSnowWorkerM1.NextId(): Int64; +begin + SyncLock.Enter; + try + if FIsOverCost then + Result := NextOverCostId() + else + Result := NextNormalId(); + finally + SyncLock.Leave; + end; +end; + +end. diff --git a/Delphi/source/Core/uSnowWorkerM2.pas b/Delphi/source/Core/uSnowWorkerM2.pas new file mode 100644 index 0000000..6e902eb --- /dev/null +++ b/Delphi/source/Core/uSnowWorkerM2.pas @@ -0,0 +1,75 @@ +unit uSnowWorkerM2; + +interface + +uses System.SysUtils, uSnowWorkerM1, uIdGeneratorOptions, System.SyncObjs; + +/// +/// ѩ㷨 +/// +type + TSnowWorkerM2 = class(TSnowWorkerM1) + public + function NextId(): Int64; + constructor Create(options: TIdGeneratorOptions); overload; + end; + +implementation + +{ TSnowWorkerM2 } + +function IncX(var x: Integer): Integer; inline; +begin + Result := x; + Inc(x); +end; + +constructor TSnowWorkerM2.Create(options: TIdGeneratorOptions); +begin + inherited Create(options); +end; + +function TSnowWorkerM2.NextId(): Int64; +var + CurrentTimeTick: Int64; +begin + SyncLock.Enter; + try + CurrentTimeTick := GetCurrentTimeTick(); + + if (FLastTimeTick = CurrentTimeTick) then + begin + // if (IncX(FCurrentSeqNumber) > FMaxSeqNumber) then + // begin + // FCurrentSeqNumber := FMinSeqNumber; + // CurrentTimeTick := GetNextTimeTick(); + // end; + if ((FCurrentSeqNumber) > FMaxSeqNumber) then + begin + FCurrentSeqNumber := FMinSeqNumber; + CurrentTimeTick := GetNextTimeTick(); + end + else + begin + Inc(FCurrentSeqNumber); + end; + end + else + begin + FCurrentSeqNumber := FMinSeqNumber; + end; + + if (CurrentTimeTick < FLastTimeTick) then + begin + raise Exception.Create(Format('Time error for %d milliseconds', [FLastTimeTick - CurrentTimeTick])); + end; + + FLastTimeTick := CurrentTimeTick; + Result := ((CurrentTimeTick shl FTimestampShift) + (Int64(FWorkerId) shl FSeqBitLength) + + Cardinal(FCurrentSeqNumber)); + finally + SyncLock.Leave; + end; +end; + +end. diff --git a/Delphi/source/Core/uSnowWorkerM3.pas b/Delphi/source/Core/uSnowWorkerM3.pas new file mode 100644 index 0000000..e90d59e --- /dev/null +++ b/Delphi/source/Core/uSnowWorkerM3.pas @@ -0,0 +1,91 @@ +unit uSnowWorkerM3; + +interface + +uses System.SysUtils, System.DateUtils, uSnowWorkerM1, uIdGeneratorOptions, System.SyncObjs; + +/// +/// ѩƯ㷨֧ID뼶ʱ +/// +type + TSnowWorkerM3 = class(TSnowWorkerM1) + protected + FDataCenterId: Cardinal; + FDataCenterIdBitLength: Byte; + FTimestampType: Byte; + protected + /// + /// IDĬ0 + /// + property DataCenterId: Cardinal read FDataCenterId default 0; + /// + /// IDȣĬ0 + /// + property DataCenterIdBitLength: Byte read FDataCenterIdBitLength default 0; + /// + /// ʱͣ0-룬1-룩Ĭ0 + /// + property TimestampType: Byte read FTimestampType default 0; + protected + function CalcId(UseTimeTick: Int64): Int64; override; + function CalcTurnBackId(UseTimeTick: Int64): Int64; override; + function GetCurrentTimeTick(): Int64; override; + public + constructor Create(options: TIdGeneratorOptions); overload; + end; + +implementation + +{ TSnowWorkerM3 } + +constructor TSnowWorkerM3.Create(options: TIdGeneratorOptions); +begin + // 뼶ʱ + FTimestampType := options.TimestampType; + + // DataCenter + FDataCenterId := options.DataCenterId; + FDataCenterIdBitLength := options.DataCenterIdBitLength; + + if (FTimestampType = 1) then + begin + FTopOverCostCount := 0; + end; + FTimestampShift := Byte(DataCenterIdBitLength + WorkerIdBitLength + SeqBitLength); + + inherited Create(options); +end; + +function TSnowWorkerM3.CalcId(UseTimeTick: Int64): Int64; +begin + Result := ((UseTimeTick shl FTimestampShift) + (Int64(DataCenterId) shl DataCenterIdBitLength) + + (Int64(WorkerId) shl SeqBitLength) + Int64(FCurrentSeqNumber)); + + Inc(FCurrentSeqNumber); +end; + +function TSnowWorkerM3.CalcTurnBackId(UseTimeTick: Int64): Int64; +begin + Result := ((UseTimeTick shl FTimestampShift) + (Int64(DataCenterId) shl DataCenterIdBitLength) + + (Int64(WorkerId) shl SeqBitLength) + FTurnBackIndex); + + Dec(FTurnBackTimeTick); +end; + +function TSnowWorkerM3.GetCurrentTimeTick: Int64; +var + Millis: Int64; +begin + if (TimestampType = 0) then + begin + Millis := GetMillisecondTimeStamp(); + Result := Millis - FBaseTime; + end + else + begin + Millis := GetSecondTimeStamp(); + Result := Millis - FBaseTime; + end; +end; + +end. diff --git a/Delphi/source/IdGenTest.dpr b/Delphi/source/IdGenTest.dpr new file mode 100644 index 0000000..8205adf --- /dev/null +++ b/Delphi/source/IdGenTest.dpr @@ -0,0 +1,25 @@ +program IdGenTest; + +uses + Vcl.Forms, + uTest in 'uTest.pas' {fTest} , + uISnowWorker in 'Contract\uISnowWorker.pas', + uIIdGenerator in 'Contract\uIIdGenerator.pas', + uTOverCostActionArg in 'Contract\uTOverCostActionArg.pas', + uIdGeneratorOptions in 'Contract\uIdGeneratorOptions.pas', + uSnowWorkerM1 in 'Core\uSnowWorkerM1.pas', + uSnowWorkerM2 in 'Core\uSnowWorkerM2.pas', + uSnowWorkerM3 in 'Core\uSnowWorkerM3.pas', + uDefaultIdGenerator in 'uDefaultIdGenerator.pas', + uYitIdHelper in 'uYitIdHelper.pas'; + +{$R *.res} + +begin + Application.Initialize; + Application.MainFormOnTaskbar := True; + ReportMemoryLeaksOnShutdown := (DebugHook <> 0); + Application.CreateForm(TfTest, fTest); + Application.Run; + +end. diff --git a/Delphi/source/IdGenTest.dproj b/Delphi/source/IdGenTest.dproj new file mode 100644 index 0000000..97237f5 --- /dev/null +++ b/Delphi/source/IdGenTest.dproj @@ -0,0 +1,987 @@ + + + {9237743A-F2B2-49BE-941B-C151799790AF} + 18.8 + VCL + IdGenTest.dpr + True + Release + Win32 + 1 + Application + + + true + + + true + Base + true + + + true + Base + true + + + true + Base + true + + + true + Cfg_1 + true + true + + + true + Base + true + + + true + Cfg_2 + true + true + + + .\$(Platform)\$(Config) + .\$(Platform)\$(Config) + false + false + false + false + false + System;Xml;Data;Datasnap;Web;Soap;Vcl;Vcl.Imaging;Vcl.Touch;Vcl.Samples;Vcl.Shell;$(DCC_Namespace) + $(BDS)\bin\delphi_PROJECTICON.ico + $(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_44.png + $(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_150.png + IdGenTest + + + DBXSqliteDriver;dxFlowChartRS26;dxPSdxMapControlLnkRS26;DBXDb2Driver;vclactnband;dxBarRS26;vclFireDAC;dxFireDACEMFRS26;tethering;KRCommon;dxSpreadSheetInplaceRichEditRS26;FireDACADSDriver;dxRichEditCoreRS26;dxPSdxSpreadSheetLnkRS26;FireDACMSSQLDriver;vcltouch;vcldb;svn;dxPSTeeChartRS26;dxGDIPlusRS26;dxPSdxFCLnkRS26;vclib;frxTee26;dxCloudServiceLibraryRS26;dxPSLnksRS26;FireDACDBXDriver;cxGridRS26;dxPsPrVwAdvRS26;dxPDFViewerRS26;vclx;dxPScxTLLnkRS26;RESTBackendComponents;VCLRESTComponents;fsTee26;vclie;bindengine;CloudService;dxmdsRS26;FireDACMySQLDriver;fsIBX26;frx26;dxdborRS26;DataSnapClient;dxFireDACServerModeRS26;bindcompdbx;fsFD26;DBXSybaseASEDriver;IndyIPServer;cxPivotGridRS26;IndySystem;frxDBX26;fsADO26;CnPack_D103R;cxTreeListdxBarPopupMenuRS26;dsnapcon;cxTreeListRS26;dxPScxPivotGridLnkRS26;cxSchedulerRibbonStyleEventEditorRS26;dxPSCoreRS26;inetwinsockets;FireDACMSAccDriver;FireDACInfxDriver;fmxFireDAC;vclimg;dxSpreadSheetRS26;dxBarExtItemsRS26;dxPSdxGaugeControlLnkRS26;emshosting;DBXOdbcDriver;FireDACTDataDriver;FMXTee;dxdbtrRS26;dxRichEditControlCoreRS26;soaprtl;DbxCommonDriver;dxFlowChartAdvancedCustomizeFormRS26;dxDockingRS26;KRWeb;xmlrtl;DataSnapNativeClient;soapmidas;fmxobj;cxLibraryRS26;rtl;emsserverresource;DbxClientDriver;DBXSybaseASADriver;dxPScxSchedulerLnkRS26;dxSpreadSheetConditionalFormattingDialogsRS26;appanalytics;dxRibbonCustomizationFormRS26;cxSchedulerGridRS26;KRFile;IndyIPClient;bindcompvcl;dxFlowChartLayoutsRS26;TeeUI;dxADOEMFRS26;VclSmp;FireDACODBCDriver;dxRibbonRS26;DataSnapIndy10ServerTransport;dxPScxCommonRS26;dxRichEditDocumentModelRS26;DataSnapProviderClient;FireDACMongoDBDriver;dxFlowChartDesignerRS26;dxPScxGridLnkRS26;dxSpreadSheetCoreRS26;DataSnapServerMidas;RESTComponents;DBXInterBaseDriver;sgcWebSocketsD10_3;dxPScxExtCommonRS26;emsclientfiredac;DataSnapFireDAC;svnui;frxFD26;DBXMSSQLDriver;dxRichEditControlRS26;DatasnapConnectorsFreePascal;dxGaugeControlRS26;dxorgcRS26;dxPScxVGridLnkRS26;bindcompfmx;DBXOracleDriver;inetdb;dxBarDBNavRS26;dxDBXServerModeRS26;SPCOMM;RaizeComponentsVcl;FmxTeeUI;emsedge;RaizeComponentsVclDb;FireDACIBDriver;fmx;fmxdae;dxServerModeRS26;dxWizardControlRS26;dxTabbedMDIRS26;fs26;dxEMFRS26;dbexpress;IndyCore;dxComnRS26;KRGraphics;frxIntIO26;dsnap;DataSnapCommon;emsclient;FireDACCommon;frxcs26;DataSnapConnectors;cxSchedulerTreeBrowserRS26;dxADOServerModeRS26;soapserver;cxPivotGridOLAPRS26;cxVerticalGridRS26;dxtrmdRS26;FireDACOracleDriver;DBXMySQLDriver;cxSchedulerRS26;cxSchedulerWebServiceStorageRS26;dxPSdxLCLnkRS26;DBXFirebirdDriver;FireDACCommonODBC;FireDACCommonDriver;dxMapControlRS26;frxIntIOIndy26;inet;dxSpellCheckerRS26;IndyIPCommon;dxSpreadSheetCoreConditionalFormattingDialogsRS26;vcl;dxPSdxDBOCLnkRS26;EhLib260;frxDB26;FireDACDb2Driver;dxSpreadSheetReportDesignerRS26;dxPScxPCProdRS26;dxNavBarRS26;fsDB26;dxCoreRS26;cxExportRS26;TeeDB;FireDAC;dxHttpIndyRequestRS26;dxPSPrVwRibbonRS26;frxe26;FireDACSqliteDriver;FireDACPgDriver;ibmonitor;FireDACASADriver;dxPSRichEditControlLnkRS26;cxPivotGridChartRS26;frxIBX26;dxPSDBTeeChartRS26;ibxpress;Tee;DataSnapServer;ibxbindings;dxPSdxDBTVLnkRS26;FireDACDSDriver;vclwinx;frxADO26;dxTileControlRS26;KRAutomation;dxSkinsCoreRS26;CustomIPTransport;vcldsnap;bindcomp;dxPSdxOCLnkRS26;DBXInformixDriver;dbxcds;adortl;dxSpreadSheetCoreDialogsRS26;dxBarExtDBItemsRS26;dsnapxml;dbrtl;IndyProtocols;inetdbxpress;dxPSdxPDFViewerLnkRS26;dxRichEditInplaceRS26;fmxase;$(DCC_UsePackage) + Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace) + Debug + true + CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments= + 1033 + $(BDS)\bin\default_app.manifest + .\ + + + DBXSqliteDriver;dxFlowChartRS26;dxPSdxMapControlLnkRS26;DBXDb2Driver;vclactnband;dxBarRS26;vclFireDAC;dxFireDACEMFRS26;tethering;dxSpreadSheetInplaceRichEditRS26;FireDACADSDriver;dxRichEditCoreRS26;dxPSdxSpreadSheetLnkRS26;FireDACMSSQLDriver;vcltouch;vcldb;dxPSTeeChartRS26;dxGDIPlusRS26;dxPSdxFCLnkRS26;vclib;dxCloudServiceLibraryRS26;dxPSLnksRS26;FireDACDBXDriver;cxGridRS26;dxPsPrVwAdvRS26;dxPDFViewerRS26;vclx;dxPScxTLLnkRS26;RESTBackendComponents;VCLRESTComponents;vclie;bindengine;CloudService;dxmdsRS26;FireDACMySQLDriver;dxdborRS26;DataSnapClient;dxFireDACServerModeRS26;bindcompdbx;DBXSybaseASEDriver;IndyIPServer;cxPivotGridRS26;IndySystem;cxTreeListdxBarPopupMenuRS26;dsnapcon;cxTreeListRS26;dxPScxPivotGridLnkRS26;cxSchedulerRibbonStyleEventEditorRS26;dxPSCoreRS26;FireDACMSAccDriver;FireDACInfxDriver;fmxFireDAC;vclimg;dxSpreadSheetRS26;dxBarExtItemsRS26;dxPSdxGaugeControlLnkRS26;emshosting;DBXOdbcDriver;FireDACTDataDriver;FMXTee;dxdbtrRS26;dxRichEditControlCoreRS26;soaprtl;DbxCommonDriver;dxFlowChartAdvancedCustomizeFormRS26;dxDockingRS26;xmlrtl;DataSnapNativeClient;soapmidas;fmxobj;cxLibraryRS26;rtl;emsserverresource;DbxClientDriver;DBXSybaseASADriver;dxPScxSchedulerLnkRS26;dxSpreadSheetConditionalFormattingDialogsRS26;appanalytics;dxRibbonCustomizationFormRS26;cxSchedulerGridRS26;IndyIPClient;bindcompvcl;dxFlowChartLayoutsRS26;TeeUI;dxADOEMFRS26;VclSmp;FireDACODBCDriver;dxRibbonRS26;DataSnapIndy10ServerTransport;dxPScxCommonRS26;dxRichEditDocumentModelRS26;DataSnapProviderClient;FireDACMongoDBDriver;dxFlowChartDesignerRS26;dxPScxGridLnkRS26;dxSpreadSheetCoreRS26;DataSnapServerMidas;RESTComponents;DBXInterBaseDriver;sgcWebSocketsD10_3;dxPScxExtCommonRS26;emsclientfiredac;DataSnapFireDAC;DBXMSSQLDriver;dxRichEditControlRS26;DatasnapConnectorsFreePascal;dxGaugeControlRS26;dxorgcRS26;dxPScxVGridLnkRS26;bindcompfmx;DBXOracleDriver;inetdb;dxBarDBNavRS26;dxDBXServerModeRS26;RaizeComponentsVcl;FmxTeeUI;emsedge;RaizeComponentsVclDb;FireDACIBDriver;fmx;fmxdae;dxServerModeRS26;dxWizardControlRS26;dxTabbedMDIRS26;dxEMFRS26;dbexpress;IndyCore;dxComnRS26;dsnap;DataSnapCommon;emsclient;FireDACCommon;DataSnapConnectors;cxSchedulerTreeBrowserRS26;dxADOServerModeRS26;soapserver;cxPivotGridOLAPRS26;cxVerticalGridRS26;dxtrmdRS26;FireDACOracleDriver;DBXMySQLDriver;cxSchedulerRS26;cxSchedulerWebServiceStorageRS26;dxPSdxLCLnkRS26;DBXFirebirdDriver;FireDACCommonODBC;FireDACCommonDriver;dxMapControlRS26;inet;dxSpellCheckerRS26;IndyIPCommon;dxSpreadSheetCoreConditionalFormattingDialogsRS26;vcl;dxPSdxDBOCLnkRS26;EhLib260;FireDACDb2Driver;dxSpreadSheetReportDesignerRS26;dxPScxPCProdRS26;dxNavBarRS26;dxCoreRS26;cxExportRS26;TeeDB;FireDAC;dxHttpIndyRequestRS26;dxPSPrVwRibbonRS26;FireDACSqliteDriver;FireDACPgDriver;ibmonitor;FireDACASADriver;dxPSRichEditControlLnkRS26;cxPivotGridChartRS26;dxPSDBTeeChartRS26;ibxpress;Tee;DataSnapServer;ibxbindings;dxPSdxDBTVLnkRS26;FireDACDSDriver;vclwinx;dxTileControlRS26;dxSkinsCoreRS26;CustomIPTransport;vcldsnap;bindcomp;dxPSdxOCLnkRS26;DBXInformixDriver;dbxcds;adortl;dxSpreadSheetCoreDialogsRS26;dxBarExtDBItemsRS26;dsnapxml;dbrtl;IndyProtocols;inetdbxpress;dxPSdxPDFViewerLnkRS26;dxRichEditInplaceRS26;fmxase;$(DCC_UsePackage) + + + DEBUG;$(DCC_Define) + true + false + true + true + true + + + false + true + PerMonitorV2 + + + false + RELEASE;$(DCC_Define) + 0 + 0 + + + true + PerMonitorV2 + true + 1033 + + + + MainSource + + +
fTest
+
+ + + + + + + + + +
$R *.res
+
+ + Cfg_2 + Base + + + Base + + + Cfg_1 + Base + +
+ + Delphi.Personality.12 + Application + + + + IdGenTest.dpr + + + Microsoft Office 2000 Sample Automation Server Wrapper Components + Microsoft Office XP Sample Automation Server Wrapper Components + + + + + + IdGenTest.exe + true + + + + + 1 + + + Contents\MacOS + 1 + + + 0 + + + + + classes + 1 + + + classes + 1 + + + + + res\xml + 1 + + + res\xml + 1 + + + + + library\lib\armeabi-v7a + 1 + + + + + library\lib\armeabi + 1 + + + library\lib\armeabi + 1 + + + + + library\lib\armeabi-v7a + 1 + + + + + library\lib\mips + 1 + + + library\lib\mips + 1 + + + + + library\lib\armeabi-v7a + 1 + + + library\lib\arm64-v8a + 1 + + + + + library\lib\armeabi-v7a + 1 + + + + + res\drawable + 1 + + + res\drawable + 1 + + + + + res\values + 1 + + + res\values + 1 + + + + + res\values-v21 + 1 + + + res\values-v21 + 1 + + + + + res\values + 1 + + + res\values + 1 + + + + + res\drawable + 1 + + + res\drawable + 1 + + + + + res\drawable-xxhdpi + 1 + + + res\drawable-xxhdpi + 1 + + + + + res\drawable-ldpi + 1 + + + res\drawable-ldpi + 1 + + + + + res\drawable-mdpi + 1 + + + res\drawable-mdpi + 1 + + + + + res\drawable-hdpi + 1 + + + res\drawable-hdpi + 1 + + + + + res\drawable-xhdpi + 1 + + + res\drawable-xhdpi + 1 + + + + + res\drawable-mdpi + 1 + + + res\drawable-mdpi + 1 + + + + + res\drawable-hdpi + 1 + + + res\drawable-hdpi + 1 + + + + + res\drawable-xhdpi + 1 + + + res\drawable-xhdpi + 1 + + + + + res\drawable-xxhdpi + 1 + + + res\drawable-xxhdpi + 1 + + + + + res\drawable-xxxhdpi + 1 + + + res\drawable-xxxhdpi + 1 + + + + + res\drawable-small + 1 + + + res\drawable-small + 1 + + + + + res\drawable-normal + 1 + + + res\drawable-normal + 1 + + + + + res\drawable-large + 1 + + + res\drawable-large + 1 + + + + + res\drawable-xlarge + 1 + + + res\drawable-xlarge + 1 + + + + + res\values + 1 + + + res\values + 1 + + + + + 1 + + + Contents\MacOS + 1 + + + 0 + + + + + Contents\MacOS + 1 + .framework + + + Contents\MacOS + 1 + .framework + + + 0 + + + + + 1 + .dylib + + + 1 + .dylib + + + 1 + .dylib + + + Contents\MacOS + 1 + .dylib + + + Contents\MacOS + 1 + .dylib + + + 0 + .dll;.bpl + + + + + 1 + .dylib + + + 1 + .dylib + + + 1 + .dylib + + + Contents\MacOS + 1 + .dylib + + + Contents\MacOS + 1 + .dylib + + + 0 + .bpl + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + Contents\Resources\StartUp\ + 0 + + + Contents\Resources\StartUp\ + 0 + + + 0 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + + + ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF + 1 + + + ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF + 1 + + + + + 1 + + + 1 + + + + + ..\ + 1 + + + ..\ + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF + 1 + + + + + ..\ + 1 + + + ..\ + 1 + + + + + Contents + 1 + + + Contents + 1 + + + + + Contents\Resources + 1 + + + Contents\Resources + 1 + + + + + library\lib\armeabi-v7a + 1 + + + library\lib\arm64-v8a + 1 + + + 1 + + + 1 + + + 1 + + + 1 + + + Contents\MacOS + 1 + + + Contents\MacOS + 1 + + + 0 + + + + + library\lib\armeabi-v7a + 1 + + + + + 1 + + + 1 + + + + + Assets + 1 + + + Assets + 1 + + + + + Assets + 1 + + + Assets + 1 + + + + + + + + + + + + + + + True + False + + + 12 + + + + +
diff --git a/Delphi/source/IdGenTest.res b/Delphi/source/IdGenTest.res new file mode 100644 index 0000000000000000000000000000000000000000..f06d283a91f0ee97e07ba9a9c373947c68db69ab GIT binary patch literal 59520 zcmV)_=zkXg0000W00030{{R60{{R30000000000000000000000ssIY00030{}2HG z{{a910000m00{&D00000000000yF>s09F7~0AB!B07U>&08;=-08ao;0ABz}08Ri# z08an_0002J1n>R;009610096100000009610000#0000000004000010000000000 z000000001B0RR9208;>T0CE6n0B!(h07d|50Bitd07(FD0A>Jh0000y0RR9205AYF z05AYK05AYF07U>a0000y015yB07d|50Bitd07L*~0CNCi0CE6n0B`_w0BHbk0B!&P z0000<0Av710A&Df08{{F0CNCz0000m00;m907d|50Bitd09F8H0CE6x0BHbk0B!&P z0000n04@M904@M904@M90000`02%-R08jvO0B-@wohLHb~j*kD4j*jemd3s;~0000000000 z00000000000001sh>47vmzV#Tm9_s{Rn-43CfNThB-;NhB-;NjCfNU3Q_=sHlCl4v zo1FiKgoT9w00000000000001$laykgoSgrTipBpiDcS!lB-;NhB-;NhB-;NhB-;Nh zB-;NhB-;NmDcS#wh{67;rl$Xmi;P1s>}Z{DcS!lB-;NhB-;Nh zB-;NhB-;NhB-;NhB-;NhB-;NhB-;NmDcS$9t<3(sxw`08RaOeIudrpt!^HnzTG;?tU*!KmI^O@3knI07EZhGqB-;Ogd+GmPSmXa*Sl0g2(b4~>rKeo6 zudk=OxWoS~CfNV4tnvT5xby#vhwJ~|-TD8NknI1sw)6j`qVNA~X666p<@^6RGTi?y zCD{MKy~h5su&|z}rl-Z5m%9EeB-;P4tnvSdgzEn+B-;O6R^tEg@BIHuMBo4G>ihri z@BIH@TI2sLB-;NhB-;O+mbv|_r>DHBr>Ml3mAC#ZB-;P4tnvSpknI0fP~rc7d+Go3 z@%{g1VC4Vj=KKHj^!@)?QsVzCB-;NhB-;O(lC}M*rlz{Jva_SLvAh2*CD;G2tnvTO z%=Z7RsPX^j=KKGsrSSi}x%2W3yQ_lW;cj*78r11Zxq3{2JeChvUT;uW##`?Pt5zq z!NLEsu(49Gu(Ao#&(G$vuFL*QMB4vWP~rbpP~rbpP~rbpP~rbpP~rbpP~rbpP~rbp zP~rbfM%(_dtH}J$%gf$-dwm7~0002e(9u-g+S>o3p3VMKOxyobOyU1hOyU1hOyU1h zOyU1hOyU1hOyU1iP2B#Xp3VB!)71UQ#>Yqi00000000000002m*x7gF;^O|q!`c3B zY0mymN8A5SN8tZXN8tZXN8J8#Y|{M0!PxxS*Vp~e&dzH900000000000000000000 z0002u;o(p2?(X6B_4WVZ;O73v#^L?Q$Kw6s;phGF@bLfU<>lPi*4IY>0000000000 z000000000000000000000002e(b5L*@9$If_4bzf`uer``T4Z;^z@VK>g!ItyuAbf z0000000000000000002+4*&q*2LJ%T0{{Sk0RR910000000000000000000000000 z00000000000001h0RRBN0{{Tv2LJ%@4*&p&2><{f00030{{sO3{{jF20000G5D5eT z000000000e0000O0000m0000103ZMW00000000000000000000000000000000000 z00000000000000000000000000000E4h{lRQd2f$VqUS6YFR#&iES6HxNUSFbN zU}1PjNJumS0s;a600000000000000000000000000000000000000000000000000 z000000000ZBP9cMbah{fhltjViHZM!e0=|JYHI&tUS9uVUS9uhYHI&}dV2qghKK%u zeSXqpV`N$h2?_%M00000000000000000000000000000000000000000001IXK5ad zi;TjiqND$tmzV#PkdXhHm!JQFex?3(aH{@vaH{@+eWU)Fm7M>Qj*kDAl$8IPmY4s7 zfPuVBOiddA0000000000000000000000000000000001ZcX=+5jgID>nwtNio}d4n zn!f*JU)KLHDAxZhB-;NhB-;NhB-;NhB-;NlDAxaDUDN)VmAL+)ot^)noSgrWkB{MA zUSBBy000000000000000000000001bdVC#|kdWq=lav3crmO#SZ_@rPCD{KgB-;Nh zB-;NhB-;NhB-;NhB-;NhB-;NhB-;NhB-;NiCD{LQYt8g&00000nF)snMva`^{ z!NLEuvDW`BCD{KgB-;NhB-;NhB-;NhB-;NhB-;NhB-;NhB-;NhB-;NhB-;NhB-;Nh zB-;NhB-;NhB-;NhB-;NiCD{M9veo|5&(Hs|u(8Ad0004(mzplWy}kd*#>f9=Vc7mG zB-;PMzV!dh%J%=v%J%=o!u9`|mF@pPIo|(URpS55%J%<>h3fw-B-;NhB-;NsMd1Isxby$}`~Lq}QsVzFC))qc&G!HG^!@)yLf`)^ zB-;NkC)NJR#moN2#KixZn3`g$sHvK-tgQc{pT+(xB-;NhB-;P+@cjR_v-1BeB-;Nh zB-;N~PvQUh`TqaCyY&A&G~NH`=llQO-1+~OlI{Qh|NsAec zoWcFNx3~YKp`whar>Cr_rKSImip2gbB-;NhB-;P+@cjR_v-1BeB-;NhB-;NqE!_Xd z#r6O5^8NosKHmR$bLap5{{R2~|NsBHxby!kB-;NhB-;NhB-;NhB-;Osg}wZ-tgQc~ zprW0rr>Lu_rKSIkh{66WB-;NhB-;P+@cjR`wDSKzINkqPQsVz$TI2uG(D(oJ^Zox| zTI2tHcNtga=+!ovQ@!^HnySj+w{CffhS z!}b5p%=iD!%=iDv$M*lHqwxP`U*!L7XXXFR%l7}TtnvR^RO0_yRO0`EeChwr%=iDB zm+k*BDBJ&8Q^@+nzrX*%zP|c>eSR1K0002V#>T_a&CUO+rN#a+D%by5QsVzuQsVzu zQsVzuQsVzuQsVzuQsVzuQsVzuQsVzuQsVzuQsVzuQsVzuQsVzuQsVzuQsVzKE!h61 zp}_jg$H)J_yuGpj000000002P!o*3|)6@Ug)6@TKXTtqbOW^-iPvQSnPvQSnPvQSn zPvQSnPvQSnPvQSnPvQSnPvQSnPvQSnPvQSnPvQSnPvQSlP2vA+X2ST>&(HtW($f8{ zt*!UOyU1iOyU1iOyU1iOyU1iOyU1i zOyU1iOyU1iOyU1iOyU1iOyU1iOyU1iOyU1$VaWK>&(ZzZ)z$yY%F3Al0000000000 z000000002P!o(5V+1l6O-QEA*+}{6tcf$QpO5FcYO5p!cO5p!cO5p!cO5p!cO5p!c zO5p!cO5p!cO5p!cO5Of|e8~CO*4X{j(b50X(9p`6nVSj#00000000000000000000 z0002b&(Iv++}zdV;^P1A?d|`#x6b}+X2bnWM%DgKN8tZXN8tZXN8tZXN8tZWN7nst zYsve(xzYROk)6~hixVjVo0000000000000000000000000000000002c z&(II!;^L$3?Ct*Z^Yj1p_4WVW-QfPZxYPZprqcYWr_=nry4L&Q;N$)C^78-e>+ApI z+1Zw{v9byP0000000000000000000000000000000000000000000000002w z+4a=%gho00000000000000000000000000 z00000000000002~0Dl1Z03QJG01p7*00#iT00RJk0097i00961000000000000000 z00000000000000000000000000001h0097i0098N00RKP00RKv00#i@01p8C06zf# z0RI4}5C8xm00030{{sO3{{sL30000G5D5eT000000000e0000W0000$0000103ZMW z00000000000000000000000000000000000000000000000000000000000000000 z0000000000000000000P85#{rN=rmmR#$aaR8^2vQc{;xQd5^!RaTEwQ&e+8LPJ3d z3kwVY000000000000000000000000000000000000000000000000000000000000 z0000000000000000000000000000000000000040R8>HAb9AbHe0=kMdwc(NadH1? zWo7?jUS9uVUS9udWo7?%a&rHFe0=|Vd3o?_YHOuKLqt0O00031000000000000000 z000000000000000000000000000000000000000000000000000000000013SXwQF zgM_`EnwtNam6iXFii-b&et!RSaB%-Ot4u+slEF4g}mB-;NhB-;NhB-;NhB-;NhB-;NhB-;NhB-;NhB-;NhB-;Nh zB-;NhB-;NhB-;NhB-;NhB-;NhB-;NhB-;NrF4h06smT7auCM>EtgQc{prP+cNlG68 z0000000000000000001?prN+0uCD*Lv$X%k!qWdfH`V_vB-;NhB-;NhB-;NhB-;Nh zB-;NhB-;NhB-;NhB-;NhB-;NhB-;NhB-;NhB-;NhB-;NhB-;NhB-;NhB-;NhB-;Nh zB-;NzH`M;Yzsvr@zrX*$y}kdGla!_a00000000000001si;XtAxVZnoy}kd=%+CL7 zX4n2KB-;NhB-;NhB-;NhB-;NhB-;NhB-;NhB-;NhB-;NhB-;NhB-;NhB-;NhB-;Nh zB-;NhB-;NhB-;NhB-;NhB-;NhB-;NhB-;NhB-;OIW77WB($fFU%gg`3zP|fbR#zzi z0000000021s;r;Fz`*~>#>fA;w%YzHBi8>dCEEWlC)@uoC)@uoC)@uoC))okB-;Nh zB-;NhB-;NhB-;NjCfffmC)@unCfffjB-;NhB-;NhB-;NhB-;NiCEEWlC)@uoC)@um zCEEWiB-j7Aw$=UB)6@Ub(9r*xn3|3N0000`P*Mf9w6*WSzrX*>$jSe1Y1sZOB-;O9 zS>yly{{R2}{{R2}{{R2}{{R2=^!@+J$oBtpZsz|iB-;OedFcQC{{R2>_Wl1%M&SP} zB-;NhB-;NhB-;O`qVNCy{{R2wW4`zrg=cP*EnPrKe}Judn~Mv$OxJsLcK>B-sBfB-;OATI2u! z|NsBwHGix|NsA#knI0C zG2H*>=KKHu|NsA-neP8AB-;NhB-;NhB-;NhB-;O{qQv~by}kdxyS)F0hl*9Frl*Fh zsi^<1tE>NzjLiNlB-;NhB-;OATI2u!|NsBxT*qq@@3Fmde#`zWB-;NhB-;OATI2u!|NsBx zN;nVWv8sHu>rrKSI> zrlihpYG~NF!B-;NhB-;NhB-;NhB-;NhB-;Oa zbHMwttE>O7s;d8-nwx#9sj7pksHp#}sj2^qhQyj-S>yj-S>yk=wDSM||NsBh)cF5jS>ykBbLap0`Tqa^|NsB#===Zw|NsBQ z!S(+*Fx>wvB-;NhB-;NhB-;NhB-;Oke!Tj#t*!sEt*!r>nVW8{tgd0Su(1EMu(1E4 zp1}SrB-sBfB-;OATI2u!|NsB%>ihp)SL6R(SL6R|NsB)?fm~{VdVc@R^tDmp6>tu|NsB? z_5J^AX664bCfffjB-;NlD9`-8xVrqix3~YixVZgXTwNMtV`BopyuIed!NLE=!o&Y$ zU&#F|B-;OATI2ur_Wu9&_Wu9&_Wu9&_Wl3u?EL@B$@c$;g6jWTRO0`8cIf}~^!@+# z_Wl2ghU))XRO0_yRO0_zRpS5C(f9xM_Wu9Q%=Z62H{Jg%B-;O8Si|_lzrX*&y}kdn zv$W6v000310002Ly}ysn$;toE%F6$#rNaIzBh~*wI^O?SQR4qtQR4qtQR4qtQR4qt zQsVzvQsVzvQsVzvQsVzuQsVzuQR4qtQR4quQsVzvQsVzvQsVzvQsVzuQsVzuQR4qt zQR4qbKHvW1INkqOQR4qsQR4qsQR4qsQR4qsQR4qsQR4qsQR4qsQR4qsQR4qsQR4qsQR4qs zQR4qsQR4qsQR4qsQR4qsQR4qsQR4qsQR4qYJl_9WRKNDm%F6%G%gg`E$jS73dwmuF z00000000000002X$;zMC)6@Ui)YSjMy~qAPIm!N2PvQSnPvQSnPvQSnPvQSnPvQSn zPvQSnPvQSnPvQSnPvQSnPvQSnPvQSnPvQSnPvQSnPvQSnPvQSnPvQSnPvQSnPvQST zJIngOyv6#|(b50d)z$yKyuF720000000000000000002CwzwD8)Ya?T*Vq5w+}!`F zrojD6MbQ3JOyU1iOyU1iOyU1iOyU1iOyU1iOyU1iOyU1iOyU1iOyU1iOyU1iOyU1i zOyU1iP2vAjOyU1iOyU1iOyU1dN7MVOsKWTz)YSjk*4F>g&(Pg`e0~f70000000000 z00000000000002X%gjvN+S>i!+}!`=+1dZp z(b50a)6@90w6!<@0000000000000000000000000000000002f($jF>+}!`*-roP~ z>FNK>%hLX8X1V=ONZbEVN#OrbN#OrbN#OrbN#OrbN#OrbN#OrbN#OrbN#OrbN#Orb zN#OraNZkH#Yr*)=%+vee-roPz(b50b)YSaL!oyeq0000000000000000000000000 z0000000000000000002j*Vk>}-QN7=n*4FpQ$jMg# z000000000000000000000000000000000000000000000000000002l+1f_t+ApV@$vuk^z{Gr_4WVU+}-}Nu*dwDl*IgrhQj-bhr|1sm&f|Iwaoh9-{Ac7^78-h z?(YBT=;;6A;o<+?+}zvB%F8wY0000000000000000000000000000000000000000 z000000000000000000000002W%F7Yx=jf2}@$vWc^z{Gs_V)kz`T76*`}_a>{r&&` z{{H{|{{H{{{r&&@`uhL(_xJzv^78-h?(YBU>FM&{-rs?zr>P16000000000000000 z0000000000000000000000000000000000000000000000000000000000000002e z(b5_0?Cg8-@$u34`1t<&`}_a>{r&&`{{H{|{{H{{{r&&@`}_a*_V)bk?d{0s=H_s` zyuA?s000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000002N!NV5j=I2H2?CoXq^Yd`> z^7C-(>+E9U;^INDu(A;V000000000000000000000000000000000000000000000 z000000000000030;0OQz0095~004jZ001BG000l*000Nz000NT000BP000Ak0004i z000310000000000000000000000000000000000000000000000001h0004i0005N z000BP000Bv000N@000m8001BS002M!004jgfC2yi@DKl}B>(^*00030{{sO3{{#R4 z0000G5D5eT000000000e0000m0001B0000103ZMW0000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z0000000000000000000000000000010RaUZ932@oH8wjxKR{JMK|)|bK|*6eK|*6d zKtfsHqQQkd)EH5u*&|ftE~TB-sBfB-;NhB-;NhB-;NhB-;NhB-;NhB-;NhB-;NhB-;Nh zB-;NhB-;NhB-;NhB-;NhB-;NhB-;NhB-;NhB-;NhB-;NhB-;NhB-;NhB-;NhB-#H~ zQP2LpyU6~irKbO(o}T}qo}T}qo}T}knVS4nRaagB0000000000000000000000000 z0000000000000000001SadS7Cn3?vQn3(^Zn3(^bo16cws;vLU#oGTwKF|IvB-;Nh zB-;NhB-;NhB-;NhB-;NhB-;NhB-;NhB-;NhB-;NhB-;NhB-;NhB-;NhB-;NhB-;Nh zB-;NhB-;NhB-;NhB-;NhB-;NhB-;NhB-;NhB-;NhB-;NhB-;N)KhXZYy3GEstE~U0 zq@@3-rKSIO9uCD*Nwz&V* z)7bx2Ptg7>B-;NhB-;NhB-;NhB-;NhB-;NhB-;NhB-;NhB-;NhB-;NhB-;NhB-;Nh zB-;NhB-;NhB-;NhB-;NhB-;NhB-;NhB-;NhB-;NhB-;NhB-;NhB-;NhB-;NhB-;Nh zB-;NhB-;NhB-;NhB-;N~PtN|$%Fh15zQ6yzyuAOty1M_gva|kOU0zuL0000000000 z00000000000000^PEZY~r>N+-wYC4cx3~Ymy}kd?&CvgcgxLNoB-sBfB-;NhB-;Nh zB-;NhB-;NhB-;NhB-;NhB-;NhB-;NhB-;NhB-;NhB-;NhB-;NhB-;NhB-;NhB-;Nh zB-;NhB-;NhB-;NhB-;NhB-;NhB-;NhB-;NhB-;NhB-;NhB-;NhB-;NhB-;NhB-;Nh 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 zLA3lxLEisWPT~JmPT~JmPT~JmPT~JmPT~JmPT~JmPT~JmPT~JmPT~JmPT~JmPT~Jm zPT~JmPT~JmPT~JmPT~JmPT~JmPT~JmPT~JmPT~JmPT~JmPT~JmPT~JmPT~JmPT~Jm zPT~JmPT~JeN8kTMKDP79$H@HD(b50b)6@Ui*4F>h(9!sejEye<000000000000000 z00000000000001ifq?r*x3Ky+}!`TwZHyBJh}W+OyK`iP2vAk zP2vAkP2vAkP2vAkP2vAkP2vAkP2vAkP2vAkP2vAkP2vAkP2vAkP2vAkP2vAkP2vAk zP2vAkP2vAkP2vAkP2vAkP2vAkP2vAkP2vAkP2vAkP2vAkP2vAjOyU1TKEL+7xxx6@ z)z$yk)YSjl*Vq5s*xCQLwz!D^0000000000000000000000000000000000000026 zu(BG~)YazP+1dZy+S>o&-roP@;o<+Vt-Ae6MY;S^OyK`gOyU1hOyU1hOyU1hOyU1h zOyU1hOyU1hOyU1hOyU1hOyU1hOyU1hOyU1hOyU1hOyU1hOyU1hOyU1hOyU1hOyU1h zOyU1hOyU1hOyU1hOyU1hOyU1hOyU1eNx=5CvcC4*+S>ou)YSjg)6@Ui)z$yY%FEAY zW@iil00000000000000000000000000000000000000000002P!o)+{+S>cw+uQ%& z+}!`;;o<-4=;;5txWN5YQLy|_O5XobOX2@fOX2@fOX2@fOX2@fOX2@fOX2@fOX2@f zOX2@fOX2@fOX2@fOX2@fOX2@fOX2@fOX2@fOX2@fOX2@fOX2@fOX2@fOX2@fOX2@e zO5gunSh@7UzQy?A-{1e()z$yg&(HtV($fFa($nvmnVTs900000000000000000000 z0000000000000000000000000000000002Y%*|xp+}!-#+uQ%&-QEA^<>mkF?Ck&3 z($oHOZl(NANYDOIN#OrbN#OrbN#OrbN#OrbN#OrbN#OrbN#OrbN#OrbN#OrbN#Orb zN#OrbN#OrbN#OrbN#OrbN#OrbN#OrbN#OrbN#OrbNz?p%c(L@>)z$pugoTgskZ%HS*!d_ zM$-OHN8tZXN8tZXN8tZXN8tZXN8tZXN8tZXN8tZXN8tZXN8tZXN8tZXN8tZXN8tZX zN8tZXN8tZWN7emgU$pnNv%vW0<>mk8+ApV@bLfh^YZ`Z<>mjXskZ!QW2E~^MZ5egxaJ=H~z4-roP(*x3Kr)z$yn+1c*8y1YXG000000000000000000000000000000 z000000000000000000000000000000000000000000000000000002c&(J&L;^W`v z<>mkD>gxaR?(YBc^78-m^z{Gr_4WVs^z{GP*x3H7s<-=ufvfswWT*OARH*t=POAA* zPOJD@R;u}HXRG&$hqCvxvA*}<-roK6^Yj1l@bLfc?d|{T>gxaH{r&&@`}_a+`1t?$`1t?)`}_a>{r&&@`}_a- z`1t?#_V)ku^Yj1l@bLfc?d|{T>FNLH<>mk7`}_a-`T76%_V)ku^Yj1l@bLfc z?d|{V?d|;G;NhvgyuBy@000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z0000000000000000002e($hEU>g%EN^Yicb_xJz!`1t?&`uhL-`}_a>{r&&`{{H{} z|NsB~{{H{|{{H{{{QUp>`}_a-`T76%_V)kv_4WVm?d|8}+F#5@bJg=_4Vud`T6|){r&&{|NsC0|NsB}{r&&=`1t$t z^YiEJ?e4zl=jevg($hhdl#~bn0000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z000000001^qooG3v$Yk*#>pkn(9tT-&(JEt!Neo1tgjP|jgAEX000000000000000 z00000000000000000000000000000000000000000000000000000000000000000 z00000000000000000030|G)$P{{R60{r~`f{{R60_y7PO{{R60-~a#z{{R60fB*mi z{{R6000000{{R5~00000e*ggd00000KL7yu000009{>RO000009{>RG000004*&q* z000002LJ%z000002LJ%T000000{{TP000000{{Sk000000RRAi000000RRAi00000 z0RRAi000000000000000000000000000000000000000000000000000000000000 z0000000000000000000000000000000000000000000000001h000000RRAi00000 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 v08Ic?06_p!07n2t08{`|000000000m00{&D00000000010000100960{Z0Mn literal 0 KcmV+b0RR6000031 diff --git a/Delphi/source/uDefaultIdGenerator.pas b/Delphi/source/uDefaultIdGenerator.pas new file mode 100644 index 0000000..80453b7 --- /dev/null +++ b/Delphi/source/uDefaultIdGenerator.pas @@ -0,0 +1,137 @@ +unit uDefaultIdGenerator; + +interface + +uses + uIIdGenerator, uISnowWorker, uIdGeneratorOptions, System.DateUtils, System.SysUtils; + +type + TDefaultIdGenerator = class(TInterfacedObject, IIdGenerator) + private + SnowWorker: ISnowWorker; + public + constructor Create(options: TIdGeneratorOptions); overload; + function NewLong(): Int64; + end; + +implementation + +uses + uSnowWorkerM1, uSnowWorkerM2, uSnowWorkerM3; + +{ TDefaultIdGenerator } + +function GetMillisecondTimeStamp(ET: TDateTime): Int64; +var + ST: TDateTime; +begin + ST := EncodeDateTime(1970, 1, 1, 0, 0, 0, 0); + Result := MilliSecondsBetween(ET, ST) - 28800000; // 8*60*60*1000; +end; + +constructor TDefaultIdGenerator.Create(options: TIdGeneratorOptions); +var + MaxLength, MaxWorkerIdNumber, MaxDataCenterIdNumber, MaxSeqNumber: Integer; +begin + if (options = nil) then + begin + raise Exception.Create('options error.'); + end; + + // 1.BaseTime + if (options.BaseTime < GetMillisecondTimeStamp(IncYear(Now(), -50))) or + (options.BaseTime > GetMillisecondTimeStamp(Now())) then + begin + raise Exception.Create('BaseTime error.'); + end; + + // 2.WorkerIdBitLength + if (options.TimestampType = 0) then + MaxLength := 22 + else + MaxLength := 31; // 뼶ʱʱŴ31λ + if (options.WorkerIdBitLength <= 0) then + begin + raise Exception.Create('WorkerIdBitLength error.(range:[1, 21])'); + end; + if (options.DataCenterIdBitLength + options.WorkerIdBitLength + options.SeqBitLength > MaxLength) then + begin + raise Exception.Create('errorDataCenterIdBitLength + WorkerIdBitLength + SeqBitLength <= ' + IntToStr(MaxLength)); + end; + + // 3.WorkerId + MaxWorkerIdNumber := (1 shl options.WorkerIdBitLength) - 1; + if (MaxWorkerIdNumber = 0) then + begin + MaxWorkerIdNumber := 63; + end; + if ((options.WorkerId < 0) or (options.WorkerId > MaxWorkerIdNumber)) then + begin + raise Exception.Create('WorkerId error. (range:[0, ' + IntToStr(MaxWorkerIdNumber) + ']'); + end; + + MaxDataCenterIdNumber := (1 shl options.DataCenterIdBitLength) - 1; + if (options.DataCenterId < 0) or (options.DataCenterId > MaxDataCenterIdNumber) then + begin + raise Exception.Create('DataCenterId error. (range:[0, ' + IntToStr(MaxDataCenterIdNumber) + ']'); + end; + + // 4.SeqBitLength + if ((options.SeqBitLength < 2) or (options.SeqBitLength > 21)) then + begin + raise Exception.Create('SeqBitLength error. (range:[2, 21])'); + end; + + // 5.MaxSeqNumber + MaxSeqNumber := (1 shl options.SeqBitLength) - 1; + if (MaxSeqNumber = 0) then + begin + MaxSeqNumber := 63; + end; + if ((options.MaxSeqNumber < 0) or (options.MaxSeqNumber > MaxSeqNumber)) then + begin + raise Exception.Create('MaxSeqNumber error. (range:[1, ' + IntToStr(MaxSeqNumber) + ']'); + end; + + // 6.MinSeqNumber + if ((options.MinSeqNumber < 5) or (options.MinSeqNumber > MaxSeqNumber)) then + begin + raise Exception.Create('MinSeqNumber error. (range:[5, ' + IntToStr(MaxSeqNumber) + ']'); + end; + + // 7.TopOverCostCount + if ((options.TopOverCostCount < 0) or (options.TopOverCostCount > 10000)) then + begin + raise Exception.Create('TopOverCostCount error. (range:[0, 10000]'); + end; + + case (options.Method) of + 2: + begin + SnowWorker := TSnowWorkerM2.Create(options); + end; + else + begin + if ((options.DataCenterIdBitLength = 0) and (options.TimestampType = 0)) then + begin + SnowWorker := TSnowWorkerM1.Create(options); + end + else + begin + SnowWorker := TSnowWorkerM3.Create(options); + end; + end; + end; + + if (options.Method <> 2) then + begin + Sleep(500); + end; +end; + +function TDefaultIdGenerator.NewLong(): Int64; +begin + Result := SnowWorker.NextId(); +end; + +end. diff --git a/Delphi/source/uTest.dfm b/Delphi/source/uTest.dfm new file mode 100644 index 0000000..e17d456 --- /dev/null +++ b/Delphi/source/uTest.dfm @@ -0,0 +1,80 @@ +object fTest: TfTest + Left = 0 + Top = 0 + Caption = #38634#33457#31639#27861#27979#35797 + ClientHeight = 509 + ClientWidth = 668 + Color = clBtnFace + Font.Charset = ANSI_CHARSET + Font.Color = clWindowText + Font.Height = -15 + Font.Name = 'Microsoft YaHei UI' + Font.Style = [] + OldCreateOrder = False + Position = poDesktopCenter + OnClose = FormClose + OnCreate = FormCreate + PixelsPerInch = 96 + TextHeight = 20 + object mmo1: TMemo + Left = 0 + Top = 100 + Width = 668 + Height = 409 + Align = alClient + ReadOnly = True + ScrollBars = ssVertical + TabOrder = 1 + end + object Panel1: TPanel + Left = 0 + Top = 0 + Width = 668 + Height = 100 + Align = alTop + Caption = 'Panel1' + ShowCaption = False + TabOrder = 0 + object Button1: TButton + Left = 32 + Top = 62 + Width = 90 + Height = 30 + Caption = #29983#25104'100'#20010 + TabOrder = 1 + OnClick = Button1Click + end + object btnTimeStamp: TButton + Left = 568 + Top = 62 + Width = 90 + Height = 30 + Caption = #27979#35797#26102#38388#25139 + TabOrder = 3 + OnClick = btnTimeStampClick + end + object Button2: TButton + Left = 168 + Top = 62 + Width = 90 + Height = 30 + Caption = '500W'#26102#38388 + TabOrder = 2 + OnClick = Button2Click + end + object rgSelect: TRadioGroup + Left = 1 + Top = 1 + Width = 666 + Height = 55 + Align = alTop + Caption = #38634#33457#31639#27861 + Columns = 3 + ItemIndex = 0 + Items.Strings = ( + #28418#31227#31639#27861 + #20256#32479#31639#27861) + TabOrder = 0 + end + end +end diff --git a/Delphi/source/uTest.pas b/Delphi/source/uTest.pas new file mode 100644 index 0000000..2dd5282 --- /dev/null +++ b/Delphi/source/uTest.pas @@ -0,0 +1,197 @@ +unit uTest; + +interface + +uses + Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, System.DateUtils, + Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.ComCtrls, Vcl.StdCtrls, Vcl.ExtCtrls, uIdGeneratorOptions, uIIdGenerator, + uDefaultIdGenerator, uYitIdHelper; + +type + TfTest = class(TForm) + mmo1: TMemo; + Panel1: TPanel; + Button1: TButton; + btnTimeStamp: TButton; + Button2: TButton; + rgSelect: TRadioGroup; + procedure Button1Click(Sender: TObject); + procedure btnTimeStampClick(Sender: TObject); + procedure Button2Click(Sender: TObject); + procedure FormCreate(Sender: TObject); + procedure FormClose(Sender: TObject; var Action: TCloseAction); + private + { Private declarations } + IdGeneratorOption: TIdGeneratorOptions; + YitIdHelper: TYitIdHelper; + public + { Public declarations } + end; + +var + fTest: TfTest; + +implementation + +{$R *.dfm} + +function GetMillisecondTimeStamp(): Int64; +var + ST: TDateTime; +begin + ST := EncodeDateTime(1970, 1, 1, 0, 0, 0, 0); + Result := MilliSecondsBetween(Now(), ST) - 28800000; // 8*60*60*1000; +end; + +procedure TfTest.btnTimeStampClick(Sender: TObject); +const + T1 = 28800000; +var + SysTime: TSystemTime; + Time1, Time2: TDateTime; + T2, T3: Int64; +begin + // 뼶 + // mmo1.Lines.Add(IntToStr(DateTimeToUnix(EncodeDateTime(2020, 2, 20, 2, 20, 2, 20), False))); + // mmo1.Lines.Add(IntToStr(DateTimeToUnix(EncodeDateTime(2020, 2, 20, 2, 20, 2, 20), True))); + // mmo1.Lines.Add(FormatDateTime('yyyy-MM-dd HH:mm:ss.zzz', + // UnixToDateTime(DateTimeToUnix(EncodeDateTime(2020, 2, 20, 2, 20, 2, 20), False), False))); + mmo1.Lines.Add('ʱתΪUTCʱ䣺' + IntToStr(DateTimeToUnix(Now(), False))); + mmo1.Lines.Add('ֱȡUTCʱ䣺' + IntToStr(DateTimeToUnix(Now(), True))); + // mmo1.Lines.Add(FormatDateTime('yyyy-MM-dd HH:mm:ss.zzz', UnixToDateTime(DateTimeToUnix(Now(), False), False))); + // mmo1.Lines.Add(FormatDateTime('yyyy-MM-dd HH:mm:ss.zzz', UnixToDateTime(DateTimeToUnix(Now(), True), True))); + + // 뼶 + Time2 := EncodeDateTime(1970, 1, 1, 0, 0, 0, 0); + + // δʱ + GetLocalTime(SysTime); + Time1 := SystemTimeToDateTime(SysTime); + T2 := MilliSecondsBetween(Time1, Time2); + T3 := T2 - T1; + mmo1.Lines.Add('LocalTime' + IntToStr(T3)); + + // ʱ + GetSystemTime(SysTime); + Time1 := SystemTimeToDateTime(SysTime); + T2 := MilliSecondsBetween(Time1, Time2); + T3 := T2 - T1; + mmo1.Lines.Add('SystemTime' + IntToStr(T3)); + + // δʱ + Time1 := Now(); + T2 := MilliSecondsBetween(Time1, Time2); + T3 := T2 - T1; + mmo1.Lines.Add('Now' + IntToStr(T3)); +end; + +procedure TfTest.Button1Click(Sender: TObject); +var + options: TIdGeneratorOptions; + IdGen: IIdGenerator; + i, j: Integer; +begin + // ʹ÷ʽһֱʹ + options := TIdGeneratorOptions.Create; + try + with options do + begin + Method := rgSelect.ItemIndex + 1; + // BaseTime := DateTime.Now.AddYears(-10); + WorkerId := 2; + + WorkerIdBitLength := 6; + SeqBitLength := 6; + + MaxSeqNumber := 0; + MinSeqNumber := 5; + + TopOverCostCount := 2000; + + DataCenterId := 0; + DataCenterIdBitLength := 0; + + TimestampType := 0; + end; + + IdGen := TDefaultIdGenerator.Create(options); + + j := 100; + Screen.Cursor := crHourGlass; + mmo1.Lines.BeginUpdate(); + try + for i := 1 to j do + begin + mmo1.Lines.Add(FormatFloat('000', i) + '' + IntToStr(IdGen.NewLong())); + end; + mmo1.Perform(WM_VSCROLL, SB_BOTTOM, 0) + finally + mmo1.Lines.EndUpdate(); + Screen.Cursor := crDefault; + end; + + finally + options.Free; + end; +end; + +procedure TfTest.Button2Click(Sender: TObject); +const + Total = 5000000; +var + i: Integer; + Id: Int64; + ST, ET, Elapse: Cardinal; +begin + Screen.Cursor := crHourGlass; + try + ST := GetTickCount(); + for i := 1 to Total do + begin + Id := YitIdHelper.NextId(); + end; + ET := GetTickCount(); + finally + Screen.Cursor := crDefault; + end; + Elapse := ET - ST; + mmo1.Lines.Add(Format('500ʱ䣺%d룬ƽÿ%d', [Elapse, Trunc((Total / Elapse) * 1000)])); + +end; + +procedure TfTest.FormClose(Sender: TObject; var Action: TCloseAction); +begin + YitIdHelper.Free; + IdGeneratorOption.Free; +end; + +procedure TfTest.FormCreate(Sender: TObject); +begin + IdGeneratorOption := TIdGeneratorOptions.Create; + // Ĭϲ + with IdGeneratorOption do + begin + Method := rgSelect.ItemIndex + 1; + // BaseTime := DateTime.Now.AddYears(-10); + WorkerId := 2; + + WorkerIdBitLength := 6; + SeqBitLength := 6; + + MaxSeqNumber := 0; + MinSeqNumber := 5; + + TopOverCostCount := 2000; + + DataCenterId := 0; + DataCenterIdBitLength := 0; + + TimestampType := 0; + end; + + // ʹ÷ʽװʹ + YitIdHelper := TYitIdHelper.Create; + YitIdHelper.SetIdGenerator(IdGeneratorOption); +end; + +end. diff --git a/Delphi/source/uYitIdHelper.pas b/Delphi/source/uYitIdHelper.pas new file mode 100644 index 0000000..fe2f185 --- /dev/null +++ b/Delphi/source/uYitIdHelper.pas @@ -0,0 +1,51 @@ +unit uYitIdHelper; + +interface + +uses System.SysUtils, uIIdGenerator, uIdGeneratorOptions; + +type + TYitIdHelper = class + private + IdGenInstance: IIdGenerator; + public + function GetIdGenInstance(): IIdGenerator; + /// + /// òʼʱִһ + /// + /// + procedure SetIdGenerator(options: TIdGeneratorOptions); + /// + /// µId + /// ñǰȷ SetIdGenerator ʼ + /// + /// + function NextId(): Int64; + end; + +implementation + +uses + uDefaultIdGenerator; + +{ TYitIdHelper } + +function TYitIdHelper.GetIdGenInstance: IIdGenerator; +begin + Result := IdGenInstance; +end; + +procedure TYitIdHelper.SetIdGenerator(options: TIdGeneratorOptions); +begin + IdGenInstance := TDefaultIdGenerator.Create(options); +end; + +function TYitIdHelper.NextId(): Int64; +begin + if (IdGenInstance = nil) then + raise Exception.Create('Please initialize Yitter.IdGeneratorOptions first.'); + + Result := IdGenInstance.NewLong(); +end; + +end. diff --git a/README.md b/README.md index ef342dd..6426dab 100644 --- a/README.md +++ b/README.md @@ -250,6 +250,7 @@ extern GoInt32 Validate(GoInt32 workerId); | 🌲 Python | [查看示例][10] | | 🌲 C | [查看示例][5] | | 🌲 C (PHP扩展) | [查看示例][7] | +| 🌲 Pascal | [查看示例][6] | | 🌲 JavaScript | [查看示例][8] | | 🌲 TypeScript | [查看示例][9] | | 🌲 V | [查看示例][6] | @@ -278,7 +279,7 @@ QQ群:646049993 [3]: https://github.com/yitter/idgenerator/tree/master/Go [4]: https://github.com/yitter/idgenerator/tree/master/Rust [5]: https://github.com/yitter/idgenerator/tree/master/C -[6]: https://github.com/yitter/idgenerator/tree/master/zzz-OtherLanguages/V +[6]: https://github.com/yitter/idgenerator/tree/master/Pascal [7]: https://github.com/yitter/idgenerator/tree/master/PHP [8]: https://github.com/yitter/IdGenerator/tree/master/JavaScript [9]: https://github.com/yitter/IdGenerator/tree/master/TypeScript @@ -289,7 +290,7 @@ QQ群:646049993 [31]: https://github.com/yitter/idgenerator/tree/master/Go [41]: https://github.com/yitter/idgenerator/tree/master/Rust [51]: https://github.com/yitter/idgenerator/tree/master/C -[61]: https://github.com/yitter/idgenerator/tree/master/zzz-OtherLanguages/V +[61]: https://github.com/yitter/idgenerator/tree/master/Pascal [71]: https://github.com/yitter/idgenerator/tree/master/PHP [72]: https://github.com/yitter/idgenerator/tree/master/zzz-OtherLanguages/D