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" }