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) }()