github.com/grafana/pyroscope@v1.18.0/pkg/block/ulid_generator.go (about) 1 package block 2 3 import ( 4 "encoding/binary" 5 "io" 6 "math/rand" 7 "time" 8 9 "github.com/cespare/xxhash/v2" 10 "github.com/oklog/ulid/v2" 11 ) 12 13 // ULIDGenerator generates deterministic ULIDs for blocks in an 14 // idempotent way: for the same set of objects, the generator 15 // will always produce the same set of ULIDs. 16 // 17 // We require block identifiers to be deterministic to ensure 18 // deduplication of the blocks. 19 type ULIDGenerator struct { 20 timestamp uint64 // Unix millis. 21 entropy io.Reader 22 } 23 24 func NewULIDGenerator(objects Objects) *ULIDGenerator { 25 if len(objects) == 0 { 26 return &ULIDGenerator{ 27 timestamp: uint64(time.Now().UnixMilli()), 28 } 29 } 30 buf := make([]byte, 0, 1<<10) 31 for _, obj := range objects { 32 buf = append(buf, obj.meta.Id...) 33 // We also include the compaction level 34 // to allow for single-block compactions. 35 buf = binary.BigEndian.AppendUint32(buf, obj.meta.CompactionLevel) 36 } 37 seed := xxhash.Sum64(buf) 38 // Reference block. 39 // We're using its timestamp in all the generated ULIDs. 40 // Assuming that the first object is the oldest one. 41 r := objects[0] 42 return &ULIDGenerator{ 43 timestamp: ulid.MustParse(r.Metadata().Id).Time(), 44 entropy: rand.New(rand.NewSource(int64(seed))), 45 } 46 } 47 48 func (g *ULIDGenerator) ULID() ulid.ULID { 49 return ulid.MustNew(g.timestamp, g.entropy) 50 }