bilibili-backup/app/admin/main/growup/util/snow_flake.go
2019-04-22 02:59:20 +00:00

66 lines
1.2 KiB
Go

package util
import (
"errors"
"sync"
"time"
)
const (
// MaxSequence max sequence in one time
MaxSequence = 1000
// WorkerBit worker bit
WorkerBit = 10
// SequenceBit sequence bit
SequenceBit = 10
)
// SnowFlake snow flake
type SnowFlake struct {
sync.Mutex
lastTimestamp int64
sequence int64
workerID int64
}
// NewSnowFlake new
func NewSnowFlake() *SnowFlake {
return &SnowFlake{
workerID: time.Now().UnixNano() % 1000,
}
}
// Generate generate
func (s *SnowFlake) Generate() (int64, error) {
s.Lock()
defer s.Unlock()
now := time.Now().UnixNano() / 1e6
if now == s.lastTimestamp {
s.sequence = (s.sequence + 1) % MaxSequence
if s.sequence == 0 {
now = s.waitNextMill(now)
}
} else {
s.sequence = 0
}
if now < s.lastTimestamp {
return 0, errors.New("inner time error")
}
s.lastTimestamp = now
return s.generate() % 1000000000, nil
}
func (s *SnowFlake) generate() int64 {
return (s.lastTimestamp << (WorkerBit + SequenceBit)) | (s.workerID << SequenceBit) | s.sequence
}
func (s *SnowFlake) waitNextMill(t int64) int64 {
for t == s.lastTimestamp {
time.Sleep(100 * time.Microsecond)
t = time.Now().UnixNano() / 1e6
}
return t
}