Skip to content

Commit

Permalink
Move sequence incrementation logic into a common struct
Browse files Browse the repository at this point in the history
  • Loading branch information
mustafaturan committed Apr 17, 2019
1 parent c499b4f commit 1e541e8
Show file tree
Hide file tree
Showing 13 changed files with 148 additions and 208 deletions.
26 changes: 7 additions & 19 deletions monoton.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,6 @@ package monoton
import (
"fmt"
"math"
"sync"

"github.com/mustafaturan/monoton/encoder"
"github.com/mustafaturan/monoton/sequencer"
Expand All @@ -70,25 +69,20 @@ const (
)

type config struct {
sync.Mutex
sequencer sequencer.Sequencer
sequencer *sequencer.Sequencer
initialTime uint
node string
timeSeqByteSize int64
seqByteSize int64
initialTime uint
}

var c config

func init() {
Configure(sequencer.NewMillisecond(), 0, 0)
}

// Configure configures the monoton with the given generator and node. If you
// need to reset the node, then you have to reconfigure. If you do not configure
// the node then the node will be set to zero value.
func Configure(s sequencer.Sequencer, node, initialTime uint) error {
c = config{sequencer: s, initialTime: initialTime}
c = config{sequencer: &s, initialTime: initialTime}

if err := configureByteSizes(); err != nil {
return err
Expand All @@ -108,25 +102,19 @@ func Configure(s sequencer.Sequencer, node, initialTime uint) error {
//
// For byte size decisions please refer to docs/adrs/byte-sizes.md
func Next() string {
t, seq := next()
t, seq := (*c.sequencer).Next()

return encoder.ToBase62WithPaddingZeros(t-c.initialTime, c.timeSeqByteSize) +
encoder.ToBase62WithPaddingZeros(seq, c.seqByteSize) +
c.node
}

func next() (uint, uint) {
c.Lock()
defer c.Unlock()

return c.sequencer.Next()
}

func configureByteSizes() error {
maxSeqTime := encoder.ToBase62(uint64(c.sequencer.MaxSequenceTime()))
sequencer := *c.sequencer
maxSeqTime := encoder.ToBase62(uint64(sequencer.MaxTime()))
c.timeSeqByteSize = int64(len(maxSeqTime))

maxSeq := encoder.ToBase62(uint64(c.sequencer.MaxSequence()))
maxSeq := encoder.ToBase62(uint64(sequencer.Max()))
c.seqByteSize = int64(len(maxSeq))

// At least one byte slot is necessary for the node
Expand Down
8 changes: 4 additions & 4 deletions monoton_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -100,11 +100,11 @@ type invalidSequencer struct {
counter uint
}

func (v *validSequencer) MaxSequenceTime() uint {
func (v *validSequencer) MaxTime() uint {
return uint(math.Pow(62, 8)) - 1
}

func (v *validSequencer) MaxSequence() uint {
func (v *validSequencer) Max() uint {
return uint(math.Pow(62, 6)) - 1
}

Expand All @@ -113,11 +113,11 @@ func (v *validSequencer) Next() (uint, uint) {
return 1, v.counter
}

func (i *invalidSequencer) MaxSequenceTime() uint {
func (i *invalidSequencer) MaxTime() uint {
return uint(math.Pow(62, 8)) - 1
}

func (i *invalidSequencer) MaxSequence() uint {
func (i *invalidSequencer) Max() uint {
return uint(math.Pow(62, 8)) - 1
}

Expand Down
2 changes: 1 addition & 1 deletion mtimer/mtimer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ func TestNow(t *testing.T) {
t1 := Now()
time.Sleep(time.Nanosecond)
t2 := Now()
if t1 == t2 {
if t1 >= t2 {
t.Errorf(
"Now() after enough sleep should increment %d = %d",
t1,
Expand Down
61 changes: 7 additions & 54 deletions sequencer/millisecond.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,59 +10,12 @@ import (
"github.com/mustafaturan/monoton/mtimer"
)

// Millisecond is monotonic millisecond time based sequencer for monoton
type Millisecond struct {
sequence uint
sequenceTime uint
}

var m *Millisecond

const (
// Maxiumum sequence time value for Millisecond sequencer
millisecondMaxSequenceTime = 62*62*62*62*62*62*62*62 - 1
// Maxiumum sequence value for Millisecond sequencer
millisecondMaxSequence = 62*62*62*62 - 1
// One millisecond in nanoseconds
millisecondInNanoseconds = uint(time.Millisecond)
)

func init() {
m = &Millisecond{sequence: 0}
m.sequenceTime = m.now()
}

// NewMillisecond returns the initialized millisecond sequencer
func NewMillisecond() *Millisecond {
return m
}

// MaxSequenceTime returns the maximum possible time sequence value
func (m *Millisecond) MaxSequenceTime() uint {
return millisecondMaxSequenceTime
}

// MaxSequence returns the maximum possible sequence value for a given time
func (m *Millisecond) MaxSequence() uint {
return millisecondMaxSequence
}

// Next increments the time and related counter sequences
func (m *Millisecond) Next() (uint, uint) {
m.incrementSequences()
return m.sequenceTime, m.sequence
}

func (m *Millisecond) incrementSequences() {
currentTime := m.now()
if currentTime > m.sequenceTime {
m.sequenceTime = currentTime
m.sequence = 0
} else {
m.sequence++
// NewMillisecond returns the preconfigured millisecond sequencer
func NewMillisecond() *Sequence {
millisecond := uint(time.Millisecond)
return &Sequence{
now: func() uint { return mtimer.Now() / millisecond },
max: 62*62*62*62 - 1,
maxTime: 62*62*62*62*62*62*62*62 - 1,
}
}

func (m *Millisecond) now() uint {
return mtimer.Now() / millisecondInNanoseconds
}
2 changes: 1 addition & 1 deletion sequencer/millisecond_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import (
)

func TestNewMillisecond(t *testing.T) {
want := reflect.TypeOf(&Millisecond{})
want := reflect.TypeOf(&Sequence{})
got := reflect.TypeOf(NewMillisecond())

if want != got {
Expand Down
60 changes: 8 additions & 52 deletions sequencer/nanosecond.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,59 +4,15 @@

package sequencer

import "github.com/mustafaturan/monoton/mtimer"

// Nanosecond is monotonic nanosecond time based sequencer for monoton
type Nanosecond struct {
sequence uint
sequenceTime uint
}

var n *Nanosecond

const (
// Maxiumum sequence time value for Nanosecond sequencer
nanosecondMaxSequenceTime = 1<<64 - 1
// Maxiumum sequence value for Nanosecond sequencer
nanosecondMaxSequence = 62*62 - 1
import (
"github.com/mustafaturan/monoton/mtimer"
)

func init() {
n = &Nanosecond{sequence: 0}
n.sequenceTime = n.now()
}

// NewNanosecond returns the initialized nanosecond sequencer
func NewNanosecond() *Nanosecond {
return n
}

// MaxSequenceTime returns the maximum possible time sequence value
func (n *Nanosecond) MaxSequenceTime() uint {
return nanosecondMaxSequenceTime
}

// MaxSequence returns the maximum possible sequence value for a given time
func (n *Nanosecond) MaxSequence() uint {
return nanosecondMaxSequence
}

// Next increments the time and related counter sequences
func (n *Nanosecond) Next() (uint, uint) {
n.incrementSequences()
return n.sequenceTime, n.sequence
}

func (n *Nanosecond) incrementSequences() {
currentTime := n.now()
if currentTime > n.sequenceTime {
n.sequenceTime = currentTime
n.sequence = 0
} else {
n.sequence++
// NewNanosecond returns the preconfigured nanosecond sequencer
func NewNanosecond() *Sequence {
return &Sequence{
now: func() uint { return mtimer.Now() },
max: 62*62 - 1,
maxTime: uint(1<<64 - 1),
}
}

func (n *Nanosecond) now() uint {
return mtimer.Now()
}
2 changes: 1 addition & 1 deletion sequencer/nanosecond_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import (
)

func TestNewNanosecond(t *testing.T) {
want := reflect.TypeOf(&Nanosecond{})
want := reflect.TypeOf(&Sequence{})
got := reflect.TypeOf(NewNanosecond())

if want != got {
Expand Down
61 changes: 7 additions & 54 deletions sequencer/second.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,59 +10,12 @@ import (
"github.com/mustafaturan/monoton/mtimer"
)

// Second is monotonic second time based sequencer for monoton
type Second struct {
sequence uint
sequenceTime uint
}

var s *Second

const (
// Maxiumum sequence time value for Second sequencer
secondMaxSequenceTime = 62*62*62*62*62*62 - 1
// Maxiumum sequence value for Second sequencer
secondMaxSequence = 62*62*62*62*62*62 - 1
// One second in nanoseconds
secondInNanoseconds = uint(time.Second)
)

func init() {
s = &Second{sequence: 0}
s.sequenceTime = s.now()
}

// NewSecond returns initialized small genarator
func NewSecond() *Second {
return s
}

// MaxSequenceTime returns the maximum possible time sequence value
func (s *Second) MaxSequenceTime() uint {
return secondMaxSequenceTime
}

// MaxSequence returns the maximum possible sequence value for a given time
func (s *Second) MaxSequence() uint {
return secondMaxSequence
}

// Next increments the time and related counter sequences
func (s *Second) Next() (uint, uint) {
s.incrementSequences()
return s.sequenceTime, s.sequence
}

func (s *Second) incrementSequences() {
currentTime := s.now()
if currentTime > s.sequenceTime {
s.sequenceTime = currentTime
s.sequence = 0
} else {
s.sequence++
// NewSecond returns the preconfigured second sequencer
func NewSecond() *Sequence {
second := uint(time.Second)
return &Sequence{
now: func() uint { return mtimer.Now() / second },
max: 62*62*62*62*62*62 - 1,
maxTime: 62*62*62*62*62*62 - 1,
}
}

func (s *Second) now() uint {
return mtimer.Now() / secondInNanoseconds
}
2 changes: 1 addition & 1 deletion sequencer/second_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import (
)

func TestNewSecond(t *testing.T) {
want := reflect.TypeOf(&Second{})
want := reflect.TypeOf(&Sequence{})
got := reflect.TypeOf(NewSecond())

if want != got {
Expand Down
42 changes: 42 additions & 0 deletions sequencer/sequence.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package sequencer

import "sync"

// Sequence is an implementation of sequencer
type Sequence struct {
sync.Mutex

current uint
time uint
max uint
maxTime uint
now func() uint
}

// Max returns the maximum possible sequence value for a given time
func (s *Sequence) Max() uint {
return s.max
}

// MaxTime returns the maximum possible time sequence value
func (s *Sequence) MaxTime() uint {
return s.maxTime
}

// Next returns the next sequence
func (s *Sequence) Next() (uint, uint) {
s.Lock()
defer s.Unlock()

s.increment()
return s.time, s.current
}

func (s *Sequence) increment() {
if s.time < s.now() {
s.time = s.now()
s.current = 0
} else {
s.current++
}
}
Loading

0 comments on commit 1e541e8

Please sign in to comment.