github.com/benz9527/xboot@v0.0.0-20240504061247-c23f15593274/lib/id/snowflake_id.go (about) 1 package id 2 3 import ( 4 "strconv" 5 "sync" 6 "time" 7 8 "github.com/benz9527/xboot/lib/infra" 9 ) 10 11 // SnowFlake 64 bits 12 // 0-00000000_00000000_00000000_00000000_00000000_0-00000_00000-00000000_0000 13 // 1 bit, as symbol, it always set as 0 14 // 41 bits, the diff val between current ts and start ts 15 // The timestamp in high bits will be affected by clock skew (clock rollback). 16 // 5 bits, as datacenter id 17 // 5 bits, as machine id 18 // 12 bits, as internal sequence number, max value is 4096 (2 ^ 12) 19 20 const ( 21 classicSnowflakeStartEpoch = int64(946659661000) // 2001-01-01 01:01:01 UTC+8 22 classicSnowflakeTsDiffBits = uint(41) 23 classicSnowflakeDIDBits = uint(5) // DataCenter ID 24 classicSnowflakeMIDBits = uint(5) // Machine ID 25 classicSnowflakeSequenceBits = uint(12) 26 classicSnowflakeMIDShiftLeft = classicSnowflakeSequenceBits 27 classicSnowflakeDIDShiftLeft = classicSnowflakeMIDShiftLeft + classicSnowflakeMIDBits 28 classicSnowflakeTsDiffShiftLeft = classicSnowflakeDIDShiftLeft + classicSnowflakeDIDBits // 22 bits 29 classicSnowflakeSequenceMax = int64(-1 ^ (-1 << classicSnowflakeSequenceBits)) 30 classicSnowflakeMIDMax = int64(-1 ^ (-1 << classicSnowflakeMIDBits)) 31 classicSnowflakeDIDMax = classicSnowflakeMIDMax 32 classicSnowflakeTsDiffMax = int64(-1 ^ (-1 << classicSnowflakeTsDiffBits)) 33 ) 34 35 type sfError string 36 37 func (e sfError) Error() string { return string(e) } 38 39 const ( 40 errSFInvalidDataCenterID = sfError("[snowflake-id] data-center id invalid") 41 errSFInvalidMachineID = sfError("[snowflake-id] machine id invalid") 42 ) 43 44 // The now function is easily to be affected by clock skew. Then 45 // the global and unique id is unstable. 46 // Deprecated: Please use the SnowFlakeID(datacenterID, machineID int64, now func() time.Time) (UUIDGen, error) 47 func StandardSnowFlakeID(dataCenterID, machineID int64, now func() time.Time) (Gen, error) { 48 if dataCenterID < 0 || dataCenterID > classicSnowflakeDIDMax { 49 return nil, infra.WrapErrorStackWithMessage(errSFInvalidDataCenterID, "dataCenterID: "+strconv.FormatInt(dataCenterID, 10)+ 50 " (max: "+strconv.FormatInt(classicSnowflakeDIDMax, 10)+")") 51 } 52 53 if machineID < 0 || machineID > classicSnowflakeMIDMax { 54 return nil, infra.WrapErrorStackWithMessage(errSFInvalidMachineID, "machineID: "+strconv.FormatInt(machineID, 10)+ 55 " (max: "+strconv.FormatInt(classicSnowflakeMIDMax, 10)+")") 56 } 57 58 var lock = sync.Mutex{} 59 lastTs, sequence := int64(0), int64(0) 60 return func() uint64 { 61 lock.Lock() 62 defer lock.Unlock() 63 64 now := now().UnixNano() / 1e6 65 if now != lastTs { 66 sequence = int64(0) 67 } else { 68 sequence = (sequence + 1) & classicSnowflakeSequenceMax 69 if sequence == 0 { 70 for now <= lastTs { 71 now = time.Now().UnixNano() / 1e6 72 } 73 } 74 } 75 76 diff := now - classicSnowflakeStartEpoch 77 if diff > classicSnowflakeTsDiffMax { 78 return 0 79 } 80 lastTs = now 81 id := (diff << classicSnowflakeTsDiffShiftLeft) | 82 (dataCenterID << classicSnowflakeDIDShiftLeft) | 83 (machineID << classicSnowflakeMIDShiftLeft) | 84 sequence 85 return uint64(id) 86 }, nil 87 } 88 89 func SnowFlakeID(dataCenterID, machineID int64, now func() time.Time) (UUIDGen, error) { 90 if dataCenterID < 0 || dataCenterID > classicSnowflakeDIDMax { 91 return nil, infra.WrapErrorStack(errSFInvalidDataCenterID) 92 } 93 94 if machineID < 0 || machineID > classicSnowflakeMIDMax { 95 return nil, infra.WrapErrorStack(errSFInvalidMachineID) 96 } 97 98 var lock = sync.Mutex{} 99 lastTs, sequence := int64(0), int64(0) 100 id := new(uuidDelegator) 101 id.number = func() uint64 { 102 lock.Lock() 103 defer lock.Unlock() 104 105 now := now().UnixNano() / 1e6 106 if now != lastTs { 107 sequence = int64(0) 108 } else { 109 sequence = (sequence + 1) & classicSnowflakeSequenceMax 110 if sequence == 0 { 111 for now <= lastTs { 112 now = time.Now().UnixNano() / 1e6 113 } 114 } 115 } 116 117 diff := now - classicSnowflakeStartEpoch 118 if diff > classicSnowflakeTsDiffMax { 119 return 0 120 } 121 lastTs = now 122 id := (diff << classicSnowflakeTsDiffShiftLeft) | 123 (dataCenterID << classicSnowflakeDIDShiftLeft) | 124 (machineID << classicSnowflakeMIDShiftLeft) | 125 sequence 126 return uint64(id) 127 } 128 id.str = func() string { 129 return strconv.FormatUint(id.number(), 10) 130 } 131 return id, nil 132 }