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  }