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 0000000..f06d283 Binary files /dev/null and b/Delphi/source/IdGenTest.res differ 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