github.com/yankunsam/loki/v2@v2.6.3-0.20220817130409-389df5235c27/pkg/usagestats/seed.go (about)

     1  package usagestats
     2  
     3  import (
     4  	"fmt"
     5  	"time"
     6  
     7  	jsoniter "github.com/json-iterator/go"
     8  	prom "github.com/prometheus/prometheus/web/api/v1"
     9  
    10  	"github.com/grafana/dskit/kv/memberlist"
    11  )
    12  
    13  // ClusterSeed is the seed for the usage stats.
    14  // A unique ID is generated for each cluster.
    15  type ClusterSeed struct {
    16  	UID                    string    `json:"UID"`
    17  	CreatedAt              time.Time `json:"created_at"`
    18  	prom.PrometheusVersion `json:"version"`
    19  }
    20  
    21  // Merge implements the memberlist.Mergeable interface.
    22  // It allow to merge the content of two different seeds.
    23  func (c *ClusterSeed) Merge(mergeable memberlist.Mergeable, localCAS bool) (change memberlist.Mergeable, error error) {
    24  	if mergeable == nil {
    25  		return nil, nil
    26  	}
    27  	other, ok := mergeable.(*ClusterSeed)
    28  	if !ok {
    29  		return nil, fmt.Errorf("expected *usagestats.ClusterSeed, got %T", mergeable)
    30  	}
    31  	if other == nil {
    32  		return nil, nil
    33  	}
    34  	// if we already have (c) the oldest key, then should not request change.
    35  	if c.CreatedAt.Before(other.CreatedAt) {
    36  		return nil, nil
    37  	}
    38  	if c.CreatedAt == other.CreatedAt {
    39  		// if we have the exact same creation date but the key is different
    40  		// we take the smallest UID using string alphabetical comparison to ensure stability.
    41  		if c.UID > other.UID {
    42  			*c = *other
    43  			return other, nil
    44  		}
    45  		return nil, nil
    46  	}
    47  	// if our seed is not the oldest, then we should request a change.
    48  	*c = *other
    49  	return other, nil
    50  }
    51  
    52  // MergeContent tells if the content of the two seeds are the same.
    53  func (c *ClusterSeed) MergeContent() []string {
    54  	return []string{c.UID}
    55  }
    56  
    57  // RemoveTombstones is not required for usagestats
    58  func (c *ClusterSeed) RemoveTombstones(limit time.Time) (total, removed int) {
    59  	return 0, 0
    60  }
    61  
    62  func (c *ClusterSeed) Clone() memberlist.Mergeable {
    63  	new := *c
    64  	return &new
    65  }
    66  
    67  var JSONCodec = jsonCodec{}
    68  
    69  type jsonCodec struct{}
    70  
    71  // todo we need to use the default codec for the rest of the code
    72  // currently crashing because the in-memory kvstore use a singleton.
    73  func (jsonCodec) Decode(data []byte) (interface{}, error) {
    74  	var seed ClusterSeed
    75  	if err := jsoniter.ConfigFastest.Unmarshal(data, &seed); err != nil {
    76  		return nil, err
    77  	}
    78  	return &seed, nil
    79  }
    80  
    81  func (jsonCodec) Encode(obj interface{}) ([]byte, error) {
    82  	return jsoniter.ConfigFastest.Marshal(obj)
    83  }
    84  func (jsonCodec) CodecID() string { return "usagestats.jsonCodec" }