123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183 |
- // Package sonyflake implements Sonyflake, a distributed unique ID generator inspired by Twitter's Snowflake.
- //
- // A Sonyflake ID is composed of
- // 39 bits for time in units of 10 msec
- // 8 bits for a sequence number
- // 16 bits for a machine id
- package sonyflake
- import (
- "errors"
- "net"
- "sync"
- "time"
- )
- // These constants are the bit lengths of Sonyflake ID parts.
- const (
- BitLenTime = 39 // bit length of time
- BitLenSequence = 8 // bit length of sequence number
- BitLenMachineID = 63 - BitLenTime - BitLenSequence // bit length of machine id
- )
- // Settings configures Sonyflake:
- //
- // StartTime is the time since which the Sonyflake time is defined as the elapsed time.
- // If StartTime is 0, the start time of the Sonyflake is set to "2014-09-01 00:00:00 +0000 UTC".
- // If StartTime is ahead of the current time, Sonyflake is not created.
- //
- // MachineID returns the unique ID of the Sonyflake instance.
- // If MachineID returns an error, Sonyflake is not created.
- // If MachineID is nil, default MachineID is used.
- // Default MachineID returns the lower 16 bits of the private IP address.
- //
- // CheckMachineID validates the uniqueness of the machine ID.
- // If CheckMachineID returns false, Sonyflake is not created.
- // If CheckMachineID is nil, no validation is done.
- type Settings struct {
- StartTime time.Time
- MachineID func() (uint16, error)
- CheckMachineID func(uint16) bool
- }
- // Sonyflake is a distributed unique ID generator.
- type Sonyflake struct {
- mutex *sync.Mutex
- startTime int64
- elapsedTime int64
- sequence uint16
- machineID uint16
- }
- // NewSonyflake returns a new Sonyflake configured with the given Settings.
- // NewSonyflake returns nil in the following cases:
- // - Settings.StartTime is ahead of the current time.
- // - Settings.MachineID returns an error.
- // - Settings.CheckMachineID returns false.
- func NewSonyflake(st Settings) *Sonyflake {
- sf := new(Sonyflake)
- sf.mutex = new(sync.Mutex)
- sf.sequence = uint16(1<<BitLenSequence - 1)
- if st.StartTime.After(time.Now()) {
- return nil
- }
- if st.StartTime.IsZero() {
- sf.startTime = toSonyflakeTime(time.Date(2014, 9, 1, 0, 0, 0, 0, time.UTC))
- } else {
- sf.startTime = toSonyflakeTime(st.StartTime)
- }
- var err error
- if st.MachineID == nil {
- sf.machineID, err = lower16BitPrivateIP()
- } else {
- sf.machineID, err = st.MachineID()
- }
- if err != nil || (st.CheckMachineID != nil && !st.CheckMachineID(sf.machineID)) {
- return nil
- }
- return sf
- }
- // NextID generates a next unique ID.
- // After the Sonyflake time overflows, NextID returns an error.
- func (sf *Sonyflake) NextID() (uint64, error) {
- const maskSequence = uint16(1<<BitLenSequence - 1)
- sf.mutex.Lock()
- defer sf.mutex.Unlock()
- current := currentElapsedTime(sf.startTime)
- if sf.elapsedTime < current {
- sf.elapsedTime = current
- sf.sequence = 0
- } else { // sf.elapsedTime >= current
- sf.sequence = (sf.sequence + 1) & maskSequence
- if sf.sequence == 0 {
- sf.elapsedTime++
- overtime := sf.elapsedTime - current
- time.Sleep(sleepTime((overtime)))
- }
- }
- return sf.toID()
- }
- const sonyflakeTimeUnit = 1e7 // nsec, i.e. 10 msec
- func toSonyflakeTime(t time.Time) int64 {
- return t.UTC().UnixNano() / sonyflakeTimeUnit
- }
- func currentElapsedTime(startTime int64) int64 {
- return toSonyflakeTime(time.Now()) - startTime
- }
- func sleepTime(overtime int64) time.Duration {
- return time.Duration(overtime)*10*time.Millisecond -
- time.Duration(time.Now().UTC().UnixNano()%sonyflakeTimeUnit)*time.Nanosecond
- }
- func (sf *Sonyflake) toID() (uint64, error) {
- if sf.elapsedTime >= 1<<BitLenTime {
- return 0, errors.New("over the time limit")
- }
- return uint64(sf.elapsedTime)<<(BitLenSequence+BitLenMachineID) |
- uint64(sf.sequence)<<BitLenMachineID |
- uint64(sf.machineID), nil
- }
- func privateIPv4() (net.IP, error) {
- as, err := net.InterfaceAddrs()
- if err != nil {
- return nil, err
- }
- for _, a := range as {
- ipnet, ok := a.(*net.IPNet)
- if !ok || ipnet.IP.IsLoopback() {
- continue
- }
- ip := ipnet.IP.To4()
- if isPrivateIPv4(ip) {
- return ip, nil
- }
- }
- return nil, errors.New("no private ip address")
- }
- func isPrivateIPv4(ip net.IP) bool {
- return ip != nil &&
- (ip[0] == 10 || ip[0] == 172 && (ip[1] >= 16 && ip[1] < 32) || ip[0] == 192 && ip[1] == 168)
- }
- func lower16BitPrivateIP() (uint16, error) {
- ip, err := privateIPv4()
- if err != nil {
- return 0, err
- }
- return uint16(ip[2])<<8 + uint16(ip[3]), nil
- }
- // Decompose returns a set of Sonyflake ID parts.
- func Decompose(id uint64) map[string]uint64 {
- const maskSequence = uint64((1<<BitLenSequence - 1) << BitLenMachineID)
- const maskMachineID = uint64(1<<BitLenMachineID - 1)
- msb := id >> 63
- time := id >> (BitLenSequence + BitLenMachineID)
- sequence := id & maskSequence >> BitLenMachineID
- machineID := id & maskMachineID
- return map[string]uint64{
- "id": id,
- "msb": msb,
- "time": time,
- "sequence": sequence,
- "machine-id": machineID,
- }
- }
|