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 }