diff --git a/.travis.yml b/.travis.yml index ea613a8..f18957f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,9 +1,7 @@ language: go go: - - 1.16.x - - master - - tip + - 1.17.x before_install: - go get golang.org/x/tools/cmd/cover diff --git a/README.md b/README.md index b772ee7..9981c6f 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ [![Build Status](https://travis-ci.org/mustafaturan/monoton.svg?branch=master)](https://travis-ci.org/mustafaturan/monoton) [![Coverage Status](https://coveralls.io/repos/github/mustafaturan/monoton/badge.svg?branch=master)](https://coveralls.io/github/mustafaturan/monoton?branch=main) [![Go Report Card](https://goreportcard.com/badge/github.com/mustafaturan/monoton)](https://goreportcard.com/report/github.com/mustafaturan/monoton) -[![GoDoc](https://godoc.org/github.com/mustafaturan/monoton?status.svg)](https://godoc.org/github.com/mustafaturan/monoton/v2) +[![GoDoc](https://godoc.org/github.com/mustafaturan/monoton?status.svg)](https://godoc.org/github.com/mustafaturan/monoton/v3) Highly scalable, single/multi node, predictable and incremental unique id generator with zero allocation magic. @@ -11,12 +11,12 @@ generator with zero allocation magic. ## Installation Via go packages: -```go get github.com/mustafaturan/monoton/v2``` +```go get github.com/mustafaturan/monoton/v3``` ## API The method names and arities/args are stable now. No change should be expected -on the package for the version `2.x.x` except any bug fixes. +on the package for the version `3.x.x` except any bug fixes. ## Usage @@ -30,8 +30,8 @@ package uniqid // Import packages import ( "fmt" - "github.com/mustafaturan/monoton/v2" - "github.com/mustafaturan/monoton/v2/sequencer" + "github.com/mustafaturan/monoton/v3" + "github.com/mustafaturan/monoton/v3/sequencer" ) var m monoton.Monoton @@ -93,8 +93,8 @@ package main // Import packages import ( "fmt" - "github.com/mustafaturan/monoton/v2" - "github.com/mustafaturan/monoton/v2/sequencer" + "github.com/mustafaturan/monoton/v3" + "github.com/mustafaturan/monoton/v3/sequencer" ) func NewIDGenerator() monoton.Monoton { @@ -187,19 +187,19 @@ implementing the `monoton/sequencer.Sequencer` interface. Command: ``` -go test -benchtime 10000000x -benchmem -run=^$ -bench=. github.com/mustafaturan/monoton/v2 +go test -benchtime 10000000x -benchmem -run=^$ -bench=. github.com/mustafaturan/monoton/v3 ``` Results: ``` goos: darwin goarch: amd64 -pkg: github.com/mustafaturan/monoton/v2 +pkg: github.com/mustafaturan/monoton/v3 cpu: Intel(R) Core(TM) i5-6267U CPU @ 2.90GHz -BenchmarkNext-4 10000000 108.7 ns/op 0 B/op 0 allocs/op -BenchmarkNextBytes-4 10000000 99.88 ns/op 0 B/op 0 allocs/op +BenchmarkNext-4 10000000 102.3 ns/op 0 B/op 0 allocs/op +BenchmarkNextBytes-4 10000000 97.51 ns/op 0 B/op 0 allocs/op PASS -ok github.com/mustafaturan/monoton/v2 2.194s +ok github.com/mustafaturan/monoton/v3 2.203s ``` ## Contributing diff --git a/benchmark_test.go b/benchmark_test.go index 58640cb..2ac08f3 100644 --- a/benchmark_test.go +++ b/benchmark_test.go @@ -3,8 +3,8 @@ package monoton_test import ( "testing" - "github.com/mustafaturan/monoton/v2" - "github.com/mustafaturan/monoton/v2/sequencer" + "github.com/mustafaturan/monoton/v3" + "github.com/mustafaturan/monoton/v3/sequencer" ) func BenchmarkNext(b *testing.B) { diff --git a/example_test.go b/example_test.go index d80f8de..6a8f060 100644 --- a/example_test.go +++ b/example_test.go @@ -8,8 +8,8 @@ import ( "fmt" "time" - "github.com/mustafaturan/monoton/v2" - "github.com/mustafaturan/monoton/v2/sequencer" + "github.com/mustafaturan/monoton/v3" + "github.com/mustafaturan/monoton/v3/sequencer" ) func ExampleNew() { diff --git a/go.mod b/go.mod index ed50bb6..db3421f 100644 --- a/go.mod +++ b/go.mod @@ -1,3 +1,3 @@ -module github.com/mustafaturan/monoton/v2 +module github.com/mustafaturan/monoton/v3 go 1.16 diff --git a/monoton.go b/monoton.go index bb019d8..2e452e6 100644 --- a/monoton.go +++ b/monoton.go @@ -60,8 +60,8 @@ Example using Singleton // Import packages import ( "fmt" - "github.com/mustafaturan/monoton/v2" - "github.com/mustafaturan/monoton/v2/sequencer" + "github.com/mustafaturan/monoton/v3" + "github.com/mustafaturan/monoton/v3/sequencer" ) const year2020asMillisecondPST = 1577865600000 @@ -117,10 +117,9 @@ package monoton import ( "fmt" - "math" - "github.com/mustafaturan/monoton/v2/encoder" - "github.com/mustafaturan/monoton/v2/sequencer" + "github.com/mustafaturan/monoton/v3/encoder" + "github.com/mustafaturan/monoton/v3/sequencer" ) const ( @@ -223,11 +222,12 @@ func (m Monoton) NextBytes() [16]byte { } func (m *Monoton) configureByteSizes() error { + maxNodeSeqByteSize := encoder.Base62ByteSize(m.sequencer.MaxNode()) maxTimeSeqByteSize := encoder.Base62ByteSize(m.sequencer.MaxTime()) maxSeqByteSize := encoder.Base62ByteSize(m.sequencer.Max()) - // At least one byte slot is necessary for the node - if maxTimeSeqByteSize+maxSeqByteSize >= totalByteSize { + // The sum is always 16 bytes + if maxTimeSeqByteSize+maxSeqByteSize+maxNodeSeqByteSize != totalByteSize { return &MaxByteSizeError{ ByteSizeSequence: maxSeqByteSize, ByteSizeSequenceTime: maxTimeSeqByteSize, @@ -251,7 +251,7 @@ func (m *Monoton) configureNode(node uint64) error { } func (m Monoton) validateNode(node uint64) error { - maxNode := uint64(math.Pow(62, float64(m.nodeByteSize()))) - 1 + maxNode := m.sequencer.MaxNode() if node > maxNode { return &MaxNodeCapacityExceededError{Node: node, MaxNode: maxNode} } diff --git a/monoton_test.go b/monoton_test.go index fc203c9..e7ff5c1 100644 --- a/monoton_test.go +++ b/monoton_test.go @@ -11,7 +11,7 @@ import ( "strings" "testing" - "github.com/mustafaturan/monoton/v2/sequencer" + "github.com/mustafaturan/monoton/v3/sequencer" ) func TestNew(t *testing.T) { @@ -148,6 +148,10 @@ type invalidSequencer struct { counter uint64 } +func (v *validSequencer) MaxNode() uint64 { + return uint64(math.Pow(62, 2)) - 1 +} + func (v *validSequencer) MaxTime() uint64 { return uint64(math.Pow(62, 8)) - 1 } @@ -161,6 +165,10 @@ func (v *validSequencer) Next() (uint64, uint64) { return 1, v.counter } +func (i *invalidSequencer) MaxNode() uint64 { + return uint64(math.Pow(62, 3)) - 1 +} + func (i *invalidSequencer) MaxTime() uint64 { return uint64(math.Pow(62, 8)) - 1 } diff --git a/sequencer/millisecond.go b/sequencer/millisecond.go index cc37a35..29cb679 100644 --- a/sequencer/millisecond.go +++ b/sequencer/millisecond.go @@ -7,7 +7,7 @@ package sequencer import ( "time" - "github.com/mustafaturan/monoton/v2/mtimer" + "github.com/mustafaturan/monoton/v3/mtimer" ) // NewMillisecond returns the preconfigured millisecond sequencer @@ -18,5 +18,6 @@ func NewMillisecond() *Sequence { now: func() uint64 { return timer.Now() / millisecond }, max: 62*62*62*62 - 1, maxTime: 62*62*62*62*62*62*62*62 - 1, + maxNode: 62*62*62*62 - 1, } } diff --git a/sequencer/nanosecond.go b/sequencer/nanosecond.go index 4fe1ded..ab95e95 100644 --- a/sequencer/nanosecond.go +++ b/sequencer/nanosecond.go @@ -5,7 +5,7 @@ package sequencer import ( - "github.com/mustafaturan/monoton/v2/mtimer" + "github.com/mustafaturan/monoton/v3/mtimer" ) // NewNanosecond returns the preconfigured nanosecond sequencer @@ -15,5 +15,6 @@ func NewNanosecond() *Sequence { now: timer.Now, max: 62*62 - 1, maxTime: uint64(1<<64 - 1), + maxNode: 62*62*62 - 1, } } diff --git a/sequencer/second.go b/sequencer/second.go index 0d317d3..e94ff8c 100644 --- a/sequencer/second.go +++ b/sequencer/second.go @@ -7,7 +7,7 @@ package sequencer import ( "time" - "github.com/mustafaturan/monoton/v2/mtimer" + "github.com/mustafaturan/monoton/v3/mtimer" ) // NewSecond returns the preconfigured second sequencer @@ -18,5 +18,6 @@ func NewSecond() *Sequence { now: func() uint64 { return timer.Now() / second }, max: 62*62*62*62*62*62 - 1, maxTime: 62*62*62*62*62*62 - 1, + maxNode: 62*62*62*62 - 1, } } diff --git a/sequencer/sequence.go b/sequencer/sequence.go index 2b4dea9..3ca3c99 100644 --- a/sequencer/sequence.go +++ b/sequencer/sequence.go @@ -14,6 +14,7 @@ type Sequence struct { time uint64 max uint64 maxTime uint64 + maxNode uint64 now func() uint64 } @@ -27,6 +28,11 @@ func (s *Sequence) MaxTime() uint64 { return s.maxTime } +// MaxNode returns the maximum possible node value +func (s *Sequence) MaxNode() uint64 { + return s.maxNode +} + // Next returns the next sequence func (s *Sequence) Next() (uint64, uint64) { now := s.now() diff --git a/sequencer/sequence_test.go b/sequencer/sequence_test.go index e115f64..5cd888c 100644 --- a/sequencer/sequence_test.go +++ b/sequencer/sequence_test.go @@ -8,7 +8,7 @@ import ( "testing" "time" - "github.com/mustafaturan/monoton/v2/mtimer" + "github.com/mustafaturan/monoton/v3/mtimer" ) func TestMax_Sequence(t *testing.T) { @@ -29,6 +29,15 @@ func TestMaxTime_Sequence(t *testing.T) { } } +func TestMaxNode_Sequence(t *testing.T) { + want := uint64(1<<64 - 1) + s := &Sequence{maxNode: want} + + if got := s.MaxNode(); got != want { + t.Errorf("Max() want: %d, got: %d", want, got) + } +} + func TestNext_Sequence(t *testing.T) { timer := mtimer.New() tests := []struct { diff --git a/sequencer/sequencer.go b/sequencer/sequencer.go index 1d37773..6712112 100644 --- a/sequencer/sequencer.go +++ b/sequencer/sequencer.go @@ -57,6 +57,8 @@ type Sequencer interface { Max() uint64 // MaxTime returns the maximum possible time sequence value MaxTime() uint64 + // MaxNode returns the maximum possible node value + MaxNode() uint64 // Now returns the current monotonic time Next() (uint64, uint64) }