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  }