// Package ulid provides thread-safe ULID (Universally Unique Lexicographically Sortable Identifier) generation. // // ULIDs are 128-bit identifiers that are lexicographically sortable and contain // a timestamp component. This package uses a pool-based approach with // cryptographically secure random seeding and monotonic ordering for optimal // performance in concurrent environments. package ulid import ( cryptorand "crypto/rand" "encoding/binary" "io" mathrand "math/rand" "os" "sync" "time" oklid "github.com/oklog/ulid/v2" "go.ntppool.org/common/logger" ) // monotonicPool is a pool of monotonic ULID readers for performance optimization. // Each reader is initialized with a cryptographically secure random seed // and random increment value to ensure uniqueness across concurrent usage. var monotonicPool = sync.Pool{ New: func() any { log := logger.Setup() var seed int64 err := binary.Read(cryptorand.Reader, binary.BigEndian, &seed) if err != nil { log.Error("crypto/rand error", "err", err) os.Exit(10) } rand := mathrand.New(mathrand.NewSource(seed)) inc := uint64(mathrand.Int63()) // log.Printf("seed: %d", seed) // log.Printf("inc: %d", inc) // inc = inc & ^uint64(1<<63) // only want 63 bits mono := oklid.Monotonic(rand, inc) return mono }, } // MakeULID generates a new ULID with the specified timestamp using a pooled monotonic reader. // The function is thread-safe and optimized for high-concurrency environments. // // Each call retrieves a monotonic reader from the pool, generates a ULID with the // given timestamp, and returns it. The reader is not returned to the pool as it // maintains internal state for monotonic ordering. // // Returns a pointer to the generated ULID or an error if generation fails. // Generation should only fail under extreme circumstances (entropy exhaustion). func MakeULID(t time.Time) (*oklid.ULID, error) { mono := monotonicPool.Get().(io.Reader) id, err := oklid.New(oklid.Timestamp(t), mono) if err != nil { return nil, err } return &id, nil }