github.com/grafana/pyroscope@v1.18.0/pkg/phlaredb/bucketindex/index.go (about)

     1  // SPDX-License-Identifier: AGPL-3.0-only
     2  // Provenance-includes-location: https://github.com/cortexproject/cortex/blob/master/pkg/storage/tsdb/bucketindex/index.go
     3  // Provenance-includes-license: Apache-2.0
     4  // Provenance-includes-copyright: The Cortex Authors.
     5  
     6  package bucketindex
     7  
     8  import (
     9  	"fmt"
    10  	"strings"
    11  	"time"
    12  
    13  	"github.com/oklog/ulid/v2"
    14  	"github.com/prometheus/common/model"
    15  
    16  	"github.com/grafana/pyroscope/pkg/phlaredb/block"
    17  	"github.com/grafana/pyroscope/pkg/phlaredb/sharding"
    18  	"github.com/grafana/pyroscope/pkg/util"
    19  )
    20  
    21  const (
    22  	IndexFilename           = "bucket-index.json"
    23  	IndexCompressedFilename = IndexFilename + ".gz"
    24  	IndexVersion1           = 1
    25  	IndexVersion2           = 2 // Added CompactorShardID field.
    26  	IndexVersion3           = 3 // Added CompactionLevel field.
    27  )
    28  
    29  // Index contains all known blocks and markers of a tenant.
    30  type Index struct {
    31  	// Version of the index format.
    32  	Version int `json:"version"`
    33  
    34  	// List of complete blocks (partial blocks are excluded from the index).
    35  	Blocks Blocks `json:"blocks"`
    36  
    37  	// List of block deletion marks.
    38  	BlockDeletionMarks BlockDeletionMarks `json:"block_deletion_marks"`
    39  
    40  	// UpdatedAt is a unix timestamp (seconds precision) of when the index has been updated
    41  	// (written in the storage) the last time.
    42  	UpdatedAt int64 `json:"updated_at"`
    43  }
    44  
    45  func (idx *Index) GetUpdatedAt() time.Time {
    46  	return time.Unix(idx.UpdatedAt, 0)
    47  }
    48  
    49  // RemoveBlock removes block and its deletion mark (if any) from index.
    50  func (idx *Index) RemoveBlock(id ulid.ULID) {
    51  	for i := 0; i < len(idx.Blocks); i++ {
    52  		if idx.Blocks[i].ID == id {
    53  			idx.Blocks = append(idx.Blocks[:i], idx.Blocks[i+1:]...)
    54  			break
    55  		}
    56  	}
    57  
    58  	for i := 0; i < len(idx.BlockDeletionMarks); i++ {
    59  		if idx.BlockDeletionMarks[i].ID == id {
    60  			idx.BlockDeletionMarks[i] = nil
    61  			idx.BlockDeletionMarks = append(idx.BlockDeletionMarks[:i], idx.BlockDeletionMarks[i+1:]...)
    62  			break
    63  		}
    64  	}
    65  }
    66  
    67  // Block holds the information about a block in the index.
    68  type Block struct {
    69  	// Block ID.
    70  	ID ulid.ULID `json:"block_id"`
    71  
    72  	// MinTime and MaxTime specify the time range all samples in the block are in (millis precision).
    73  	MinTime model.Time `json:"min_time"`
    74  	MaxTime model.Time `json:"max_time"`
    75  
    76  	// UploadedAt is a unix timestamp (seconds precision) of when the block has been completed to be uploaded
    77  	// to the storage.
    78  	UploadedAt int64 `json:"uploaded_at"`
    79  
    80  	// Block's compactor shard ID, copied from tsdb.CompactorShardIDExternalLabel label.
    81  	CompactorShardID string `json:"compactor_shard_id,omitempty"`
    82  	CompactionLevel  int    `json:"compaction_level,omitempty"`
    83  }
    84  
    85  // Within returns whether the block contains samples within the provided range.
    86  // Input minT and maxT are both inclusive.
    87  func (m *Block) Within(minT, maxT model.Time) bool {
    88  	return block.InRange(m.MinTime, m.MaxTime, minT, maxT)
    89  }
    90  
    91  func (m *Block) GetUploadedAt() time.Time {
    92  	return time.Unix(m.UploadedAt, 0)
    93  }
    94  
    95  func (m *Block) String() string {
    96  	minT := util.TimeFromMillis(int64(m.MinTime)).UTC()
    97  	maxT := util.TimeFromMillis(int64(m.MaxTime)).UTC()
    98  
    99  	shard := m.CompactorShardID
   100  	if shard == "" {
   101  		shard = "none"
   102  	}
   103  
   104  	return fmt.Sprintf("%s (min time: %s max time: %s, compactor shard: %s)", m.ID, minT.String(), maxT.String(), shard)
   105  }
   106  
   107  // Meta returns a block meta based on the known information in the index.
   108  // The returned meta doesn't include all original meta.json data but only a subset
   109  // of it.
   110  func (m *Block) Meta() *block.Meta {
   111  	return &block.Meta{
   112  		ULID:    m.ID,
   113  		MinTime: m.MinTime,
   114  		MaxTime: m.MaxTime,
   115  		Labels: map[string]string{
   116  			sharding.CompactorShardIDLabel: m.CompactorShardID,
   117  		},
   118  		Compaction: block.BlockMetaCompaction{
   119  			Level: m.CompactionLevel,
   120  		},
   121  	}
   122  }
   123  
   124  func BlockFromMeta(meta block.Meta) *Block {
   125  	return &Block{
   126  		ID:               meta.ULID,
   127  		MinTime:          meta.MinTime,
   128  		MaxTime:          meta.MaxTime,
   129  		CompactorShardID: meta.Labels[sharding.CompactorShardIDLabel],
   130  		CompactionLevel:  meta.Compaction.Level,
   131  	}
   132  }
   133  
   134  // BlockDeletionMark holds the information about a block's deletion mark in the index.
   135  type BlockDeletionMark struct {
   136  	// Block ID.
   137  	ID ulid.ULID `json:"block_id"`
   138  
   139  	// DeletionTime is a unix timestamp (seconds precision) of when the block was marked to be deleted.
   140  	DeletionTime int64 `json:"deletion_time"`
   141  }
   142  
   143  func (m *BlockDeletionMark) GetDeletionTime() time.Time {
   144  	return time.Unix(m.DeletionTime, 0)
   145  }
   146  
   147  // BlockDeletionMark returns the block deletion mark.
   148  func (m *BlockDeletionMark) BlockDeletionMark() *block.DeletionMark {
   149  	return &block.DeletionMark{
   150  		ID:           m.ID,
   151  		Version:      block.DeletionMarkVersion1,
   152  		DeletionTime: m.DeletionTime,
   153  	}
   154  }
   155  
   156  func DeletionMarkFromBlockMarker(mark *block.DeletionMark) *BlockDeletionMark {
   157  	return &BlockDeletionMark{
   158  		ID:           mark.ID,
   159  		DeletionTime: mark.DeletionTime,
   160  	}
   161  }
   162  
   163  // BlockDeletionMarks holds a set of block deletion marks in the index. No ordering guaranteed.
   164  type BlockDeletionMarks []*BlockDeletionMark
   165  
   166  func (s BlockDeletionMarks) GetULIDs() []ulid.ULID {
   167  	ids := make([]ulid.ULID, len(s))
   168  	for i, m := range s {
   169  		ids[i] = m.ID
   170  	}
   171  	return ids
   172  }
   173  
   174  func (s BlockDeletionMarks) Clone() BlockDeletionMarks {
   175  	clone := make(BlockDeletionMarks, len(s))
   176  	for i, m := range s {
   177  		v := *m
   178  		clone[i] = &v
   179  	}
   180  	return clone
   181  }
   182  
   183  // Blocks holds a set of blocks in the index. No ordering guaranteed.
   184  type Blocks []*Block
   185  
   186  func (s Blocks) GetULIDs() []ulid.ULID {
   187  	ids := make([]ulid.ULID, len(s))
   188  	for i, m := range s {
   189  		ids[i] = m.ID
   190  	}
   191  	return ids
   192  }
   193  
   194  func (s Blocks) String() string {
   195  	b := strings.Builder{}
   196  
   197  	for idx, m := range s {
   198  		if idx > 0 {
   199  			b.WriteString(", ")
   200  		}
   201  		b.WriteString(m.String())
   202  	}
   203  
   204  	return b.String()
   205  }