| | |
| | | package snowflake |
| | | |
| | | import ( |
| | | "errors" |
| | | "strconv" |
| | | "sync" |
| | | "time" |
| | | "apsClient/pkg/logx" |
| | | "fmt" |
| | | "github.com/bwmarrin/snowflake" |
| | | "hash/fnv" |
| | | "net" |
| | | ) |
| | | |
| | | const ( |
| | | CEpoch = 1474802888000 |
| | | CWorkerIdBits = 10 // Num of WorkerId Bits |
| | | CSenquenceBits = 12 // Num of Sequence Bits |
| | | var Node *snowflake.Node |
| | | |
| | | CWorkerIdShift = 12 |
| | | CTimeStampShift = 22 |
| | | |
| | | CSequenceMask = 0xfff // equal as getSequenceMask() |
| | | CMaxWorker = 0x3ff // equal as getMaxWorkerId() |
| | | ) |
| | | |
| | | type IdWorker struct { |
| | | workerId int64 |
| | | lastTimeStamp int64 |
| | | sequence int64 |
| | | maxWorkerId int64 |
| | | lock *sync.Mutex |
| | | } |
| | | |
| | | func NewIdWorker(workerId int64) (iw *IdWorker, err error) { |
| | | iw = new(IdWorker) |
| | | |
| | | iw.maxWorkerId = getMaxWorkerId() |
| | | |
| | | if workerId > iw.maxWorkerId || workerId < 0 { |
| | | return nil, errors.New("worker not fit") |
| | | func Init(nodeId string) error { |
| | | // Create a new Node with a Node number of 1 |
| | | var err error |
| | | nodeIdInt, err := StringToNumber(nodeId) |
| | | if err != nil { |
| | | logx.Errorf("snowflake Init error:%v", err) |
| | | return err |
| | | } |
| | | iw.workerId = workerId |
| | | iw.lastTimeStamp = -1 |
| | | iw.sequence = 0 |
| | | iw.lock = new(sync.Mutex) |
| | | return iw, nil |
| | | } |
| | | |
| | | func getMaxWorkerId() int64 { |
| | | return -1 ^ -1<<CWorkerIdBits |
| | | } |
| | | |
| | | func getSequenceMask() int64 { |
| | | return -1 ^ -1<<CSenquenceBits |
| | | } |
| | | |
| | | // return in ms |
| | | func (iw *IdWorker) timeGen() int64 { |
| | | return time.Now().UnixNano() / 1000 / 1000 |
| | | } |
| | | |
| | | func (iw *IdWorker) timeReGen(last int64) int64 { |
| | | ts := time.Now().UnixNano() / 1000 / 1000 |
| | | for { |
| | | if ts <= last { |
| | | ts = iw.timeGen() |
| | | } else { |
| | | break |
| | | } |
| | | Node, err = snowflake.NewNode(nodeIdInt) |
| | | if err != nil { |
| | | logx.Errorf("snowflake NewNode error:%v", err) |
| | | return err |
| | | } |
| | | return ts |
| | | return nil |
| | | } |
| | | |
| | | func (iw *IdWorker) NextId() (ts int64, err error) { |
| | | iw.lock.Lock() |
| | | defer iw.lock.Unlock() |
| | | ts = iw.timeGen() |
| | | if ts == iw.lastTimeStamp { |
| | | iw.sequence = (iw.sequence + 1) & CSequenceMask |
| | | if iw.sequence == 0 { |
| | | ts = iw.timeReGen(ts) |
| | | } |
| | | } else { |
| | | iw.sequence = 0 |
| | | } |
| | | |
| | | if ts < iw.lastTimeStamp { |
| | | err = errors.New("Clock moved backwards, Refuse gen id") |
| | | func StringToNumber(input string) (int64, error) { |
| | | hash := fnv.New32a() |
| | | _, err := hash.Write([]byte(input)) |
| | | if err != nil { |
| | | return 0, err |
| | | } |
| | | iw.lastTimeStamp = ts |
| | | ts = (ts-CEpoch)<<CTimeStampShift | iw.workerId<<CWorkerIdShift | iw.sequence |
| | | return ts, nil |
| | | hashValue := int64(hash.Sum32()) |
| | | return hashValue, nil |
| | | } |
| | | |
| | | func ParseId(id int64) (t time.Time, ts int64, workerId int64, seq int64) { |
| | | seq = id & CSequenceMask |
| | | workerId = (id >> CWorkerIdShift) & CMaxWorker |
| | | ts = (id >> CTimeStampShift) + CEpoch |
| | | t = time.Unix(ts/1000, (ts%1000)*1000000) |
| | | return |
| | | } |
| | | |
| | | var idGenerater, _ = NewIdWorker(0) |
| | | |
| | | func GenerateId() int64 { |
| | | start: |
| | | id, err := idGenerater.NextId() |
| | | if err != nil { |
| | | goto start |
| | | func GenerateID() int64 { |
| | | if Node == nil { |
| | | // 使用 LookupIP 获取主机的 IP 地址列表 |
| | | addrs, err := net.LookupIP("localhost") |
| | | if err != nil { |
| | | logx.Infof("snowflake can not generate, init error, get ip error:%v", err) |
| | | panic(fmt.Sprintf("snowflake can not generate, init error, get ip error:%v", err)) |
| | | } |
| | | var ip string |
| | | // 遍历 IP 地址列表 |
| | | for _, addr := range addrs { |
| | | // 判断 IP 地址的版本是 IPv4 还是 IPv6 |
| | | if ipNet := addr.To4(); ipNet != nil { |
| | | ip = ipNet.String() |
| | | fmt.Printf("IPv4 Address: %s\n", ipNet.String()) |
| | | } |
| | | } |
| | | err = Init(ip) |
| | | if err != nil { |
| | | panic(fmt.Sprintf("snowflake can not generate, init error,:%v", err)) |
| | | } |
| | | } |
| | | return id |
| | | } |
| | | |
| | | func GenerateIdStr() string { |
| | | start: |
| | | id, err := idGenerater.NextId() |
| | | if err != nil { |
| | | goto start |
| | | } |
| | | return strconv.FormatInt(id, 10) |
| | | return int64(Node.Generate()) |
| | | } |