You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.
package tools
import (
"github.com/metacubex/mihomo/log"
"sync"
"time"
)
const (
epoch = int64 ( 1577808000000 ) // 设置起始时间(时间戳/毫秒): 2020-01-01 00:00:00, 有效期69年
timestampBits = uint ( 41 ) // 时间戳占用位数
datacenteridBits = uint ( 5 ) // 数据中心id所占位数
workeridBits = uint ( 5 ) // 机器id所占位数
sequenceBits = uint ( 12 ) // 序列所占的位数
timestampMax = int64 ( - 1 ^ ( - 1 << timestampBits ) ) // 时间戳最大值
sequenceMask = int64 ( - 1 ^ ( - 1 << sequenceBits ) ) // 支持的最大序列id数量
workeridShift = sequenceBits // 机器id左移位数
datacenteridShift = sequenceBits + workeridBits // 数据中心id左移位数
timestampShift = sequenceBits + workeridBits + datacenteridBits // 时间戳左移位数
)
type snowflake struct {
sync . Mutex
timestamp int64
workerid int64
datacenterid int64
sequence int64
}
var s = & snowflake {
timestamp : 0 ,
datacenterid : 1 ,
workerid : 2 ,
sequence : 0 ,
}
func SnowflakeId ( ) int64 {
return s . nextVal ( )
}
// nextVal 返回下一个Snowflake ID
func ( s * snowflake ) nextVal ( ) int64 {
s . Lock ( )
now := time . Now ( ) . UnixNano ( ) / 1000000 // 转毫秒
if s . timestamp == now {
// 当同一时间戳( 精度: 毫秒) 下多次生成id会增加序列号
s . sequence = ( s . sequence + 1 ) & sequenceMask
if s . sequence == 0 {
// 如果当前序列超出12bit长度, 则需要等待下一毫秒
// 下一毫秒将使用sequence:0
for now <= s . timestamp {
now = time . Now ( ) . UnixNano ( ) / 1000000
}
}
} else {
// 不同时间戳( 精度: 毫秒) 下直接使用序列号: 0
s . sequence = 0
}
t := now - epoch
if t > timestampMax {
s . Unlock ( )
log . Fatalln ( "epoch must be between 0 and %d" , timestampMax - 1 )
return 0
}
s . timestamp = now
r := ( t ) << timestampShift | ( s . datacenterid << datacenteridShift ) | ( s . workerid << workeridShift ) | ( s . sequence )
s . Unlock ( )
return r
}