101 lines
1.9 KiB
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)
|
|
}()
|