github.com/benz9527/xboot@v0.0.0-20240504061247-c23f15593274/lib/id/monotonic_id.go (about) 1 package id 2 3 import ( 4 "strconv" 5 "sync/atomic" 6 "unsafe" 7 8 "golang.org/x/sys/cpu" 9 ) 10 11 const cacheLinePadSize = unsafe.Sizeof(cpu.CacheLinePad{}) 12 13 // monotonicNonZeroID is an ID generator. 14 // Only increase, if it overflows, it will be reset to 1. 15 // Occupy a whole cache line (flag+tag+data), and a cache line data is 64 bytes. 16 // L1D cache: cat /sys/devices/system/cpu/cpu0/cache/index0/coherency_line_size 17 // L1I cache: cat /sys/devices/system/cpu/cpu0/cache/index1/coherency_line_size 18 // L2 cache: cat /sys/devices/system/cpu/cpu0/cache/index2/coherency_line_size 19 // L3 cache: cat /sys/devices/system/cpu/cpu0/cache/index3/coherency_line_size 20 // MESI (Modified-Exclusive-Shared-Invalid) 21 // RAM data -> L3 cache -> L2 cache -> L1 cache -> CPU register. 22 // CPU register (cache hit) -> L1 cache -> L2 cache -> L3 cache -> RAM data. 23 type monotonicNonZeroID struct { 24 // sequence consistency data race free program 25 // avoid load into cpu cache will be broken by others data 26 // to compose a data race cache line 27 _ [cacheLinePadSize - unsafe.Sizeof(*new(uint64))]byte // padding for CPU cache line, avoid false sharing 28 val uint64 // space waste to exchange for performance 29 _ [cacheLinePadSize - unsafe.Sizeof(*new(uint64))]byte // padding for CPU cache line, avoid false sharing 30 } 31 32 func (id *monotonicNonZeroID) next() uint64 { 33 // Golang atomic store with LOCK prefix, it means that 34 // it implements the Happens-Before relationship. 35 // But it is not clearly that atomic add satisfies the 36 // Happens-Before relationship. 37 // https://go.dev/ref/mem 38 var v uint64 39 if v = atomic.AddUint64(&id.val, 1); v == 0 { 40 v = atomic.AddUint64(&id.val, 1) 41 } 42 return v 43 } 44 45 func MonotonicNonZeroID() (UUIDGen, error) { 46 src := &monotonicNonZeroID{val: 0} 47 id := new(uuidDelegator) 48 id.number = func() uint64 { 49 return src.next() 50 } 51 id.str = func() string { 52 return strconv.FormatUint(src.next(), 10) 53 } 54 return id, nil 55 }