automated snapshot
This commit is contained in:
93
internal/ids/ids.go
Normal file
93
internal/ids/ids.go
Normal file
@@ -0,0 +1,93 @@
|
||||
// k ordered id generator
|
||||
package ids
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
// 2024-07-03T00:00:00Z
|
||||
customEpochMs int64 = 1719964800000
|
||||
|
||||
seqBits = 8
|
||||
workerBits = 16
|
||||
timeBits = 40
|
||||
|
||||
seqMask = (1 << seqBits) - 1 // 0xFF
|
||||
workerMask = (1 << workerBits) - 1 // 0xFFFF
|
||||
timeMask = (int64(1) << timeBits) - 1 // low 40 bits
|
||||
|
||||
workerShift = seqBits
|
||||
timeShift = workerBits + seqBits
|
||||
)
|
||||
|
||||
// Generator is safe for concurrent use.
|
||||
type Generator struct {
|
||||
workerID uint64
|
||||
mu sync.Mutex
|
||||
lastMs int64
|
||||
sequence uint64
|
||||
}
|
||||
|
||||
func NewGenerator(workerID uint32) (*Generator, error) {
|
||||
if workerID > workerMask {
|
||||
return nil, errors.New("workerID too large for 16 bits")
|
||||
}
|
||||
return &Generator{workerID: uint64(workerID)}, nil
|
||||
}
|
||||
|
||||
func (g *Generator) Next() (uint64, error) {
|
||||
nowMs := time.Now().UTC().UnixMilli()
|
||||
delta := nowMs - customEpochMs
|
||||
if delta < 0 {
|
||||
return 0, errors.New("time is before custom epoch")
|
||||
}
|
||||
if delta > timeMask {
|
||||
return 0, errors.New("timestamp overflow (40-bit ms range exceeded)")
|
||||
}
|
||||
|
||||
g.mu.Lock()
|
||||
defer g.mu.Unlock()
|
||||
|
||||
if delta == g.lastMs {
|
||||
g.sequence = (g.sequence + 1) & seqMask
|
||||
if g.sequence == 0 {
|
||||
// sequence wrapped; wait for next millisecond
|
||||
for delta == g.lastMs {
|
||||
nowMs = time.Now().UTC().UnixMilli()
|
||||
delta = nowMs - customEpochMs
|
||||
}
|
||||
}
|
||||
} else {
|
||||
g.sequence = 0
|
||||
g.lastMs = delta
|
||||
}
|
||||
|
||||
id := (uint64(delta) << timeShift) |
|
||||
((g.workerID & workerMask) << workerShift) |
|
||||
(g.sequence & seqMask)
|
||||
|
||||
return id, nil
|
||||
}
|
||||
|
||||
// ---- Base62 ----
|
||||
|
||||
const base62Alphabet = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
|
||||
|
||||
func Base62Encode(x uint64) string {
|
||||
if x == 0 {
|
||||
return "0"
|
||||
}
|
||||
var buf [11]byte // 62^11 > 2^64, so max 11 chars
|
||||
i := len(buf)
|
||||
for x > 0 {
|
||||
r := x % 62
|
||||
x /= 62
|
||||
i--
|
||||
buf[i] = base62Alphabet[r]
|
||||
}
|
||||
return string(buf[i:])
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user