package generator import ( "errors" "sync" "time" ) const ( epoch = int64(1609459200000) datacenterIdBits = uint(5) workerIdBits = uint(5) sequenceBits = uint(12) maxDatacenterId = -1 ^ (-1 << datacenterIdBits) maxWorkerId = -1 ^ (-1 << workerIdBits) maxSequence = -1 ^ (-1 << sequenceBits) workerIdShift = sequenceBits datacenterIdShift = sequenceBits + workerIdBits timestampLeftShift = sequenceBits + workerIdBits + datacenterIdBits ) type Snowflake struct { mu sync.Mutex timestamp int64 datacenterId int64 workerId int64 sequence int64 } func NewSnowflake(datacenterId, workerId int64) (*Snowflake, error) { if datacenterId < 0 || datacenterId > maxDatacenterId { return nil, errors.New("datacenter id must be between 0 and 31") } if workerId < 0 || workerId > maxWorkerId { return nil, errors.New("worker id must be between 0 and 31") } return &Snowflake{ timestamp: 0, datacenterId: datacenterId, workerId: workerId, sequence: 0, }, nil } func (s *Snowflake) NextID() (int64, error) { s.mu.Lock() defer s.mu.Unlock() now := time.Now().UnixMilli() if now < s.timestamp { return 0, errors.New("clock moved backwards") } if now == s.timestamp { s.sequence = (s.sequence + 1) & maxSequence if s.sequence == 0 { for now <= s.timestamp { now = time.Now().UnixMilli() } } } else { s.sequence = 0 } s.timestamp = now id := ((now - epoch) << timestampLeftShift) | (s.datacenterId << datacenterIdShift) | (s.workerId << workerIdShift) | s.sequence return id, nil } func (s *Snowflake) NextIDs(count int) ([]int64, error) { if count <= 0 || count > 1000 { return nil, errors.New("count must be between 1 and 1000") } ids := make([]int64, count) for i := 0; i < count; i++ { id, err := s.NextID() if err != nil { return nil, err } ids[i] = id } return ids, nil }