-
Notifications
You must be signed in to change notification settings - Fork 13
/
Copy pathDxSnowflake.pas
131 lines (119 loc) · 3.15 KB
/
DxSnowflake.pas
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
//Delphi版雪花算法
//作者:不得闲
//https://github.com/suiyunonghen/DelphiSnowflake
//QQ: 75492895
unit DxSnowflake;
interface
uses {$IF Defined(MSWINDOWS)}Winapi.Windows{$ELSEIF Defined(MACOS)}Macapi.Mach,Macapi.ObjCRuntime
{$ELSEIF Defined(POSIX)}Posix.Time{$ENDIF},System.SysUtils,System.Generics.Collections,System.DateUtils;
type
TWorkerID = 0..1023;
TDxSnowflake = class
private
FStartUnix: int64;
FWorkerID: TWorkerID;
fTime: Int64;
fstep: int64;
FStartEpoch: Int64;
freq: Int64;
startC: Int64;
function CurrentUnix: Int64;
public
constructor Create(StartTime: TDateTime);
destructor Destroy;override;
property WorkerID: TWorkerID read FWorkerID write FWorkerID;
function Generate: Int64;
end;
implementation
const
Epoch: int64 = 1539615188; //北京时间2018-10-15号
//工作站的节点位数
WorkerNodeBits:Byte = 10;
//序列号的节点数
StepBits: Byte = 12;
timeShift: Byte = 22;
nodeShift: Byte = 12;
var
WorkerNodeMax: int64;
nodeMask:int64;
stepMask:int64;
procedure InitNodeInfo;
begin
WorkerNodeMax := -1 xor (-1 shl WorkerNodeBits);
nodeMask := WorkerNodeMax shl StepBits;
stepMask := -1 xor (-1 shl StepBits);
end;
{ TDxSnowflake }
constructor TDxSnowflake.Create(StartTime: TDateTime);
{$IF Defined(POSIX)}
var
res: timespec;
{$ENDIF}
begin
if StartTime >= Now then
FStartEpoch := DateTimeToUnix(IncMinute(Now,-2))
else if YearOf(StartTime) < 1950 then
FStartEpoch := Epoch
else FStartEpoch := DateTimeToUnix(StartTime);
FStartEpoch := FStartEpoch * 1000;//ms
FStartUnix := DateTimeToUnix(Now) * 1000;
//获得系统的高性能频率计数器在一毫秒内的震动次数
{$IF Defined(MSWINDOWS)}
queryperformancefrequency(freq);
QueryPerformanceCounter(startC);
{$ELSEIF Defined(MACOS)}
startC := AbsoluteToNanoseconds(mach_absolute_time) div 1000000;
{$ELSEIF Defined(POSIX)}
clock_gettime(CLOCK_MONOTONIC, @res);
startC := (Int64(1000000000) * res.tv_sec + res.tv_nsec) div 1000000;
{$ENDIF}
end;
function TDxSnowflake.CurrentUnix: Int64;
var
nend: Int64;
{$IF Defined(POSIX)}
res: timespec;
{$ENDIF}
begin
{$IF Defined(MSWINDOWS)}
QueryPerformanceCounter(nend);
Result := FStartUnix + (nend - startC) * 1000 div freq;
{$ELSEIF Defined(MACOS)}
nend := AbsoluteToNanoseconds(mach_absolute_time) div 1000000;
Result := FStartUnix + nend - startC;
{$ELSEIF Defined(POSIX)}
clock_gettime(CLOCK_MONOTONIC, @res);
nend := (Int64(1000000000) * res.tv_sec + res.tv_nsec) div 1000000;
Result := FStartUnix + nend - startC;
{$ENDIF}
end;
destructor TDxSnowflake.Destroy;
begin
inherited;
end;
function TDxSnowflake.Generate: Int64;
var
curtime: Int64;
begin
TMonitor.Enter(Self);
try
curtime := CurrentUnix;//DateTimeToUnix(Now) * 1000;
if curtime = fTime then
begin
fstep := (fstep + 1) and stepMask;
if fstep = 0 then
begin
while curtime <= fTime do
curtime := CurrentUnix;//DateTimeToUnix(Now) * 1000;
end;
end
else fstep := 0;
fTime := curtime;
Result := (curtime - FStartEpoch) shl timeShift or FWorkerID shl nodeShift or fstep;
finally
TMonitor.Exit(Self);
end;
end;
initialization
InitNodeInfo;
end.