// 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<= 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<= 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<> 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, } }