github.com/nsqio/nsq@v1.3.0/nsqd/guid.go (about) 1 package nsqd 2 3 // the core algorithm here was borrowed from: 4 // Blake Mizerany's `noeqd` https://github.com/bmizerany/noeqd 5 // and indirectly: 6 // Twitter's `snowflake` https://github.com/twitter/snowflake 7 8 // only minor cleanup and changes to introduce a type, combine the concept 9 // of workerID + datacenterId into a single identifier, and modify the 10 // behavior when sequences rollover for our specific implementation needs 11 12 import ( 13 "encoding/hex" 14 "errors" 15 "sync" 16 "time" 17 ) 18 19 const ( 20 nodeIDBits = uint64(10) 21 sequenceBits = uint64(12) 22 nodeIDShift = sequenceBits 23 timestampShift = sequenceBits + nodeIDBits 24 sequenceMask = int64(-1) ^ (int64(-1) << sequenceBits) 25 26 // ( 2012-10-28 16:23:42 UTC ).UnixNano() >> 20 27 twepoch = int64(1288834974288) 28 ) 29 30 var ErrTimeBackwards = errors.New("time has gone backwards") 31 var ErrSequenceExpired = errors.New("sequence expired") 32 var ErrIDBackwards = errors.New("ID went backward") 33 34 type guid int64 35 36 type guidFactory struct { 37 sync.Mutex 38 39 nodeID int64 40 sequence int64 41 lastTimestamp int64 42 lastID guid 43 } 44 45 func NewGUIDFactory(nodeID int64) *guidFactory { 46 return &guidFactory{ 47 nodeID: nodeID, 48 } 49 } 50 51 func (f *guidFactory) NewGUID() (guid, error) { 52 f.Lock() 53 54 // divide by 1048576, giving pseudo-milliseconds 55 ts := time.Now().UnixNano() >> 20 56 57 if ts < f.lastTimestamp { 58 f.Unlock() 59 return 0, ErrTimeBackwards 60 } 61 62 if f.lastTimestamp == ts { 63 f.sequence = (f.sequence + 1) & sequenceMask 64 if f.sequence == 0 { 65 f.Unlock() 66 return 0, ErrSequenceExpired 67 } 68 } else { 69 f.sequence = 0 70 } 71 72 f.lastTimestamp = ts 73 74 id := guid(((ts - twepoch) << timestampShift) | 75 (f.nodeID << nodeIDShift) | 76 f.sequence) 77 78 if id <= f.lastID { 79 f.Unlock() 80 return 0, ErrIDBackwards 81 } 82 83 f.lastID = id 84 85 f.Unlock() 86 87 return id, nil 88 } 89 90 func (g guid) Hex() MessageID { 91 var h MessageID 92 var b [8]byte 93 94 b[0] = byte(g >> 56) 95 b[1] = byte(g >> 48) 96 b[2] = byte(g >> 40) 97 b[3] = byte(g >> 32) 98 b[4] = byte(g >> 24) 99 b[5] = byte(g >> 16) 100 b[6] = byte(g >> 8) 101 b[7] = byte(g) 102 103 hex.Encode(h[:], b[:]) 104 return h 105 }