snowflake-uid-service/main.go

101 lines
1.9 KiB
Go

package main
import (
"hash/fnv"
"log"
"os"
"strconv"
"sync"
"sync/atomic"
"time"
)
func main() {
log.Println(host_10b)
log.Println(epoch)
log.Println(epoch.UnixNano() / int64(time.Millisecond) / 10)
log.Println(ts_41b())
for i := 0; i < 7; i++ {
time.Sleep(time.Duration(i) * time.Millisecond)
log.Printf("%v = ts_41b/%v/seq_13b/%v/host_10b/%v", id(), ts_41b(), seq_13b(), host_10b)
}
}
func id() uint64 {
ts := ts_41b() << (64 - 41)
seq := seq_13b() << (64 - 41 - 13)
host := host_10b
return ts | seq | host
}
func ts_41b() uint64 {
durationSinceEpoch := time.Now().Sub(epoch)
return uint64(durationSinceEpoch/time.Millisecond) / 10
}
var seqLock = &sync.RWMutex{}
var seqV = &atomic.Uint64{}
var seqTS = &atomic.Int64{}
func seq_13b() uint64 {
_seq_13b_rollover()
got := func() uint64 {
seqLock.RLock()
defer seqLock.RUnlock()
return seqV.Add(1)
}()
if got > (1 << 13) {
time.Sleep(time.Millisecond * 10)
return seq_13b()
}
return got
}
func _seq_13b_now() int64 {
return time.Now().UnixNano() / int64(time.Millisecond) / 10
}
func _seq_13b_rollover() {
now := _seq_13b_now()
if seqTS.Load() == now {
return
}
func() {
seqLock.Lock()
defer seqLock.Unlock()
if seqTS.Load() == now {
return
}
seqTS.Store(now)
seqV.Store(0)
}()
}
var epoch = func() time.Time {
t := time.Unix(0, 0)
if v := os.Getenv("SNOWFLAKE_UID_SERVICE_EPOCH"); v != "" {
// RFC3339 = "2006-01-02T15:04:05Z07:00"
t2, err := time.ParseInLocation(time.RFC3339, v, time.UTC)
if err != nil {
panic(err)
}
t = t2
}
return t // uint64(t.UnixNano() / int64(time.Millisecond) / 10)
}()
var host_10b = func() uint64 {
if v := os.Getenv("SNOWFLAKE_UID_SERVICE_HOST"); v != "" {
v, err := strconv.ParseUint(v, 10, 10)
if err != nil {
panic(err)
}
ui64 := uint64(v)
return uint64(ui64 << 54 >> 54)
}
hash := fnv.New32()
hash.Write([]byte(os.Getenv("HOSTNAME")))
ui32 := hash.Sum32()
return uint64((ui32 << 22) >> 22)
}()