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 }