github.com/yankunsam/loki/v2@v2.6.3-0.20220817130409-389df5235c27/pkg/storage/stores/tsdb/index/shard.go (about) 1 package index 2 3 import ( 4 "errors" 5 "fmt" 6 "math" 7 8 "github.com/prometheus/common/model" 9 ) 10 11 const ( 12 // ShardLabel is a reserved label referencing a cortex shard 13 ShardLabel = "__tsdb_shard__" 14 // ShardLabelFmt is the fmt of the ShardLabel key. 15 ShardLabelFmt = "%d_of_%d" 16 ) 17 18 var errDisallowedIdentityShard = errors.New("shard with factor of 1 is explicitly disallowed. It's equivalent to no sharding") 19 20 // ShardAnnotation is a convenience struct which holds data from a parsed shard label 21 // Of MUST be a power of 2 to ensure sharding logic works correctly. 22 type ShardAnnotation struct { 23 Shard uint32 24 Of uint32 25 } 26 27 func NewShard(x, of uint32) ShardAnnotation { 28 return ShardAnnotation{ 29 Shard: x, 30 Of: of, 31 } 32 } 33 34 // Match returns whether a fingerprint belongs to a certain shard. 35 // The Shard must be a power of 2. 36 // Inclusion in a shard is calculated by determining the arbitrary bit prefix 37 // for a shard, then ensuring the fingerprint has the same prefix 38 func (shard ShardAnnotation) Match(fp model.Fingerprint) bool { 39 if shard.Of < 2 { 40 return true 41 } 42 requiredBits := shard.RequiredBits() 43 44 // A shard only matches a fingerprint when they both start with the same prefix 45 return uint64(shard.Shard) == uint64(fp)>>(64-requiredBits) 46 } 47 48 // String encodes a shardAnnotation into a label value 49 func (shard ShardAnnotation) String() string { 50 return fmt.Sprintf(ShardLabelFmt, shard.Shard, shard.Of) 51 } 52 53 func (shard ShardAnnotation) RequiredBits() uint64 { 54 // The minimum number of bits required to represent shard.Of 55 return uint64(math.Log2(float64(shard.Of))) 56 57 } 58 59 func (shard ShardAnnotation) Validate() error { 60 if shard.Of == 1 { 61 return errDisallowedIdentityShard 62 } 63 64 if 1<<shard.RequiredBits() != shard.Of { 65 return fmt.Errorf("Shard factor must be a power of two, got %d", shard.Of) 66 } 67 return nil 68 } 69 70 // Bounds shows the [minimum, maximum) fingerprints. If there is no maximum 71 // fingerprint (for example the last shard), math.MaxUint64 is used as the maximum. 72 func (shard ShardAnnotation) Bounds() (model.Fingerprint, model.Fingerprint) { 73 requiredBits := model.Fingerprint(shard.RequiredBits()) 74 from := model.Fingerprint(shard.Shard) << (64 - requiredBits) 75 76 if shard.Shard+1 == shard.Of { 77 return from, model.Fingerprint(math.MaxUint64) 78 } 79 return from, model.Fingerprint(shard.Shard+1) << (64 - requiredBits) 80 }