Skip to content

Instantly share code, notes, and snippets.

@thetooth
Last active April 16, 2019 04:12
Show Gist options
  • Save thetooth/c795fee8b9afce946d24c7b612fefdde to your computer and use it in GitHub Desktop.
Save thetooth/c795fee8b9afce946d24c7b612fefdde to your computer and use it in GitHub Desktop.
package seq
import (
"fmt"
"time"
)
// DSN type for global ordering
type DSN struct {
Value uint64
}
func (s *DSN) String() string {
return fmt.Sprintf("%v", s.Value)
}
// Time returns the time.Time of when the DSN was created
func (s *DSN) Time() time.Time {
var timestamp = int64(s.Value >> 22)
return time.Unix(timestamp, 0)
}
// Machine returns the machine identifier
func (s *DSN) Machine() uint {
return uint(s.Value & ((1 << 10) - 1))
}
// Sequence returns the message sequence number
func (s *DSN) Sequence() uint {
return uint(s.Value & ((1 << 12) - 1))
}
// Explain format
func (s *DSN) Explain() {
var timestamp = int64(s.Value >> 22)
var machine = s.Value & ((1 << 10) - 1)
var sequence = s.Value & ((1 << 12) - 1)
fmt.Printf(" %v%v%v\n", pad.Right("Time", 42, " "), pad.Right("Machine", 10, " "), pad.Right("Sequence", 12, " "))
fmt.Printf(" %v%v%v\n\n", pad.Right(time.Unix(timestamp, 0).String(), 42, " "), pad.Left(fmt.Sprint(machine), 10, " "), pad.Left(fmt.Sprint(sequence), 12, " "))
fmt.Printf(" %v\n", pad.Right(fmt.Sprintf("%042b", timestamp), 64, "."))
fmt.Printf(" %v\n", pad.Left(pad.Right(fmt.Sprintf("%010b", machine), 22, "."), 64, "."))
fmt.Printf(" %v\n\n", pad.Left(fmt.Sprintf("%012b", sequence), 64, "."))
fmt.Printf(" (timestamp << 22) | (machine << 12) | sequence == %v\n\n", s.String())
}
// New returns a new sequence type, if time stamp is 0, returns a new sequence
// with the current local time
func New(timestamp int64, machine, sequence uint) *DSN {
if timestamp == 0 {
timestamp = time.Now().Unix()
}
// 41 bit | 10 bit | 12 bit
return &DSN{Value: uint64(timestamp<<22) | uint64(machine<<12) | uint64(sequence)}
}
func times(str string, n int) (out string) {
for i := 0; i < n; i++ {
out += str
}
return
}
// Left left-pads the string with pad up to len runes
// len may be exceeded if
func Left(str string, len int, pad string) string {
return times(pad, len-utf8.RuneCountInString(str)) + str
}
// Right right-pads the string with pad up to len runes
func Right(str string, len int, pad string) string {
return str + times(pad, len-utf8.RuneCountInString(str))
}
package seq_test
import (
"testing"
"time"
"github.com/thetooth/test2/seq"
)
func TestNew(t *testing.T) {
var timestamp = time.Date(2018, 1, 1, 12, 34, 0, 0, time.Local).Unix()
var machine uint = 0x3FF
var sequence uint = 0xFFF
s := seq.New(timestamp, machine, sequence)
s.Explain()
if s.Value != 0x169265c43fffff {
t.Errorf("s.Value invalid %#x != 0x169265c43fffff", s.Value)
}
if s.String() != "////odzMpAsAAA==" {
t.Errorf("s.String() invalid %s != ////odzMpAsAAA==", s)
}
if s.Time() != time.Date(2018, 1, 1, 12, 34, 0, 0, time.Local) {
t.Errorf("s.Time() invalid")
}
if s.Machine() != 1023 {
t.Errorf("s.Machine() invalid")
}
if s.Sequence() != 4095 {
t.Errorf("s.Sequence() invalid")
}
}
func BenchmarkNew(b *testing.B) {
for i := 0; i < b.N; i++ {
s := seq.New(0, uint(i), uint(i))
b.Log(s)
}
}
func BenchmarkGetters(b *testing.B) {
s := seq.New(time.Now().Unix(), 53, 1056)
for i := 0; i < b.N; i++ {
t := s.Time()
m := s.Machine()
seq := s.Sequence()
b.Log(t, m, seq)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment