1 module yu.algorithm.snowflkeId;
2 
3 import std.datetime;
4 import yu.time;
5 import core.atomic;
6 import core.thread;
7 
8 /**
9  * Twitter's Snowflke ID generate algorithm.to generate only ID
10  * 
11  * workerIdBits : 工作机器的ID所占的位数,支持不存在workID
12  * seqBits : 计数器位数,默认: 10个位用来保存计数码
13  * twepoch :  开始的时间戳,ms。默认为 2017-3-1 0:0:0.0
14 */
15 
16 alias SnowflkeID = SnowflkeBase!(4);
17 
18 final class SnowflkeBase(int workerIdBits, int sequenceBits = 10, long twepoch = 1488297600000L)
19         if (sequenceBits > 0 && twepoch > 0)
20 {
21     enum long maxSequence = -1L ^ -1L << sequenceBits; //一毫秒内可以产生计数,如果达到该值则等到下一微妙在进行生成
22     static if (workerIdBits > 0)
23     {
24         enum long maxWorkerId = -1L ^ -1L << workerIdBits; //最大机器ID
25         enum int timestampLeftShift = sequenceBits + workerIdBits; //时间戳左移动位数就是机器码和计数器位数
26     }
27     else
28     {
29         enum int timestampLeftShift = sequenceBits; //时间戳左移动位数就是机器码和计数器位数
30     }
31 
32     static if (workerIdBits > 0)
33     {
34         this(long macid)
35         in
36         {
37             assert(macid <= maxWorkerId && macid >= 0);
38         }
39         body
40         {
41             macId = macid;
42         }
43 
44         @property MacId() const nothrow{return macId;}
45     }
46 
47     long generate()
48     {
49         long timestamp;
50         synchronized (this)
51         {
52             timestamp = stdToUinxTimeMs(Clock.currStdTime); // 获取毫秒数
53             if (lastTime >= timestamp)
54             {
55                 sequence += 1;
56             }
57             else
58             {
59                 lastTime = timestamp;
60                 sequence = 0;
61             }
62             if (sequence > maxSequence)
63             {
64                 while (true)
65                 {
66                     timestamp = stdToUinxTimeMs(Clock.currStdTime); // 获取毫秒数
67                     if (timestamp > lastTime)
68                         break;
69                 }
70                 lastTime = timestamp;
71                 sequence = 0;
72             }
73         }
74         static if (workerIdBits > 0)
75         {
76             return (((timestamp - twepoch) << timestampLeftShift) | (macId << sequenceBits)
77                     | sequence);
78         }
79         else
80         {
81             return (((timestamp - twepoch) << timestampLeftShift) | sequence);
82         }
83     }
84 
85 protected:
86     void witeToNext()
87     {
88         while (true)
89         {
90             long timestamp = stdToUinxTimeMs(Clock.currStdTime); // 获取毫秒数
91             if (timestamp > lastTime)
92                 return;
93         }
94     }
95 
96 private:
97     static if (workerIdBits > 0)
98         long macId;
99     long sequence = 0;
100     long lastTime = 0;
101 }
102 
103 unittest
104 {
105     import std.stdio;
106 
107     SnowflkeID sny = new SnowflkeID(0);
108 
109     writeln("SnowflkeID : ", stdToUinxTimeMs(Clock.currStdTime));
110     long last = -1;
111     foreach (i; 0 .. 10000)
112     {
113         long now = sny.generate();
114         assert(last != now);
115     }
116     writeln("SnowflkeID : end ", stdToUinxTimeMs(Clock.currStdTime));
117 
118     auto sny2 = new SnowflkeBase!(0,15)();
119      writeln("SnowflkeID : ", stdToUinxTimeMs(Clock.currStdTime));
120     foreach (i; 0 .. 10000)
121     {
122         long now = sny.generate();
123         assert(last != now);
124     }
125     writeln("SnowflkeID : end ", stdToUinxTimeMs(Clock.currStdTime));
126 }