Use int64

This commit is contained in:
Yoshiyuki Mineo
2025-05-02 02:33:06 +09:00
parent eccf7b77c8
commit c847588763
4 changed files with 41 additions and 43 deletions

View File

@@ -27,7 +27,7 @@ Installation
------------
```
go get github.com/sony/sonyflake
go get github.com/sony/sonyflake/v2
```
Usage
@@ -44,8 +44,8 @@ You can configure Sonyflake by the struct Settings:
```go
type Settings struct {
StartTime time.Time
MachineID func() (uint16, error)
CheckMachineID func(uint16) bool
MachineID func() (int64, error)
CheckMachineID func(int64) bool
}
```
@@ -65,16 +65,12 @@ type Settings struct {
In order to get a new unique ID, you just have to call the method NextID.
```go
func (sf *Sonyflake) NextID() (uint64, error)
func (sf *Sonyflake) NextID() (int64, error)
```
NextID can continue to generate IDs for about 174 years from StartTime.
But after the Sonyflake time is over the limit, NextID returns an error.
> **Note:**
> Sonyflake currently does not use the most significant bit of IDs,
> so you can convert Sonyflake IDs from `uint64` to `int64` safely.
AWS VPC and Docker
------------------

View File

@@ -34,13 +34,13 @@ func amazonEC2PrivateIPv4() (net.IP, error) {
// AmazonEC2MachineID retrieves the private IP address of the Amazon EC2 instance
// and returns its lower 16 bits.
// It works correctly on Docker as well.
func AmazonEC2MachineID() (uint16, error) {
func AmazonEC2MachineID() (int64, error) {
ip, err := amazonEC2PrivateIPv4()
if err != nil {
return 0, err
}
return uint16(ip[2])<<8 + uint16(ip[3]), nil
return int64(uint16(ip[2])<<8 + uint16(ip[3])), nil
}
// TimeDifference returns the time difference between the localhost and the given NTP server.

View File

@@ -39,8 +39,8 @@ const (
// If CheckMachineID is nil, no validation is done.
type Settings struct {
StartTime time.Time
MachineID func() (uint16, error)
CheckMachineID func(uint16) bool
MachineID func() (int64, error)
CheckMachineID func(int64) bool
}
// Sonyflake is a distributed unique ID generator.
@@ -48,8 +48,8 @@ type Sonyflake struct {
mutex *sync.Mutex
startTime int64
elapsedTime int64
sequence uint16
machineID uint16
sequence int64
machineID int64
}
var (
@@ -73,10 +73,10 @@ func New(st Settings) (*Sonyflake, error) {
sf := new(Sonyflake)
sf.mutex = new(sync.Mutex)
sf.sequence = uint16(1<<BitLenSequence - 1)
sf.sequence = int64(1<<BitLenSequence - 1)
if st.StartTime.IsZero() {
sf.startTime = toSonyflakeTime(time.Date(2014, 9, 1, 0, 0, 0, 0, time.UTC))
sf.startTime = toSonyflakeTime(time.Date(2025, 1, 1, 0, 0, 0, 0, time.UTC))
} else {
sf.startTime = toSonyflakeTime(st.StartTime)
}
@@ -110,8 +110,10 @@ func NewSonyflake(st Settings) *Sonyflake {
// 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)
// NextID generates a next unique ID as int64.
// After the Sonyflake time overflows, NextID returns an error.
func (sf *Sonyflake) NextID() (int64, error) {
const maskSequence = int64(1<<BitLenSequence - 1)
sf.mutex.Lock()
defer sf.mutex.Unlock()
@@ -147,14 +149,14 @@ func sleepTime(overtime int64) time.Duration {
time.Duration(time.Now().UTC().UnixNano()%sonyflakeTimeUnit)
}
func (sf *Sonyflake) toID() (uint64, error) {
func (sf *Sonyflake) toID() (int64, error) {
if sf.elapsedTime >= 1<<BitLenTime {
return 0, ErrOverTimeLimit
}
return uint64(sf.elapsedTime)<<(BitLenSequence+BitLenMachineID) |
uint64(sf.sequence)<<BitLenMachineID |
uint64(sf.machineID), nil
return sf.elapsedTime<<(BitLenSequence+BitLenMachineID) |
sf.sequence<<BitLenMachineID |
sf.machineID, nil
}
func privateIPv4(interfaceAddrs types.InterfaceAddrs) (net.IP, error) {
@@ -183,43 +185,43 @@ func isPrivateIPv4(ip net.IP) bool {
(ip[0] == 10 || ip[0] == 172 && (ip[1] >= 16 && ip[1] < 32) || ip[0] == 192 && ip[1] == 168 || ip[0] == 169 && ip[1] == 254)
}
func lower16BitPrivateIP(interfaceAddrs types.InterfaceAddrs) (uint16, error) {
func lower16BitPrivateIP(interfaceAddrs types.InterfaceAddrs) (int64, error) {
ip, err := privateIPv4(interfaceAddrs)
if err != nil {
return 0, err
}
return uint16(ip[2])<<8 + uint16(ip[3]), nil
return int64(ip[2])<<8 + int64(ip[3]), nil
}
// ElapsedTime returns the elapsed time when the given Sonyflake ID was generated.
func ElapsedTime(id uint64) time.Duration {
func ElapsedTime(id int64) time.Duration {
return time.Duration(elapsedTime(id) * sonyflakeTimeUnit)
}
func elapsedTime(id uint64) uint64 {
func elapsedTime(id int64) int64 {
return id >> (BitLenSequence + BitLenMachineID)
}
// SequenceNumber returns the sequence number of a Sonyflake ID.
func SequenceNumber(id uint64) uint64 {
const maskSequence = uint64((1<<BitLenSequence - 1) << BitLenMachineID)
return id & maskSequence >> BitLenMachineID
func SequenceNumber(id int64) int64 {
const maskSequence = int64((1<<BitLenSequence - 1) << BitLenMachineID)
return (id & maskSequence) >> BitLenMachineID
}
// MachineID returns the machine ID of a Sonyflake ID.
func MachineID(id uint64) uint64 {
const maskMachineID = uint64(1<<BitLenMachineID - 1)
func MachineID(id int64) int64 {
const maskMachineID = int64(1<<BitLenMachineID - 1)
return id & maskMachineID
}
// Decompose returns a set of Sonyflake ID parts.
func Decompose(id uint64) map[string]uint64 {
func Decompose(id int64) map[string]int64 {
msb := id >> 63
time := elapsedTime(id)
sequence := SequenceNumber(id)
machineID := MachineID(id)
return map[string]uint64{
return map[string]int64{
"id": id,
"msb": msb,
"time": time,

View File

@@ -15,7 +15,7 @@ import (
var sf *Sonyflake
var startTime int64
var machineID uint64
var machineID int64
func init() {
var st Settings
@@ -29,10 +29,10 @@ func init() {
startTime = toSonyflakeTime(st.StartTime)
ip, _ := lower16BitPrivateIP(defaultInterfaceAddrs)
machineID = uint64(ip)
machineID = int64(ip)
}
func nextID(t *testing.T) uint64 {
func nextID(t *testing.T) int64 {
id, err := sf.NextID()
if err != nil {
t.Fatal("id not generated")
@@ -58,7 +58,7 @@ func TestNew(t *testing.T) {
{
name: "failure: machine ID",
settings: Settings{
MachineID: func() (uint16, error) {
MachineID: func() (int64, error) {
return 0, genError
},
},
@@ -67,7 +67,7 @@ func TestNew(t *testing.T) {
{
name: "failure: invalid machine ID",
settings: Settings{
CheckMachineID: func(uint16) bool {
CheckMachineID: func(int64) bool {
return false
},
},
@@ -125,8 +125,8 @@ func currentTime() int64 {
func TestSonyflakeFor10Sec(t *testing.T) {
var numID uint32
var lastID uint64
var maxSequence uint64
var lastID int64
var maxSequence int64
initial := currentTime()
current := initial
@@ -179,7 +179,7 @@ func TestSonyflakeInParallel(t *testing.T) {
runtime.GOMAXPROCS(numCPU)
fmt.Println("number of cpu:", numCPU)
consumer := make(chan uint64)
consumer := make(chan int64)
const numID = 10000
generate := func() {
@@ -193,7 +193,7 @@ func TestSonyflakeInParallel(t *testing.T) {
go generate()
}
set := make(map[uint64]struct{})
set := make(map[int64]struct{})
for i := 0; i < numID*numGenerator; i++ {
id := <-consumer
if _, ok := set[id]; ok {
@@ -270,7 +270,7 @@ func TestPrivateIPv4(t *testing.T) {
func TestLower16BitPrivateIP(t *testing.T) {
testCases := []struct {
description string
expected uint16
expected int64
interfaceAddrs types.InterfaceAddrs
error string
}{