@@ -53,6 +53,7 @@ type LifecyclerConfig struct {
53
53
NormaliseTokens bool `yaml:"normalise_tokens,omitempty"`
54
54
InfNames []string `yaml:"interface_names"`
55
55
FinalSleep time.Duration `yaml:"final_sleep"`
56
+ TokensFilePath string `yaml:"tokens_file_path,omitempty"`
56
57
57
58
// For testing, you can override the address and ID of this ingester
58
59
Addr string `yaml:"address"`
@@ -84,6 +85,7 @@ func (cfg *LifecyclerConfig) RegisterFlagsWithPrefix(prefix string, f *flag.Flag
84
85
flagext .DeprecatedFlag (f , prefix + "claim-on-rollout" , "DEPRECATED. This feature is no longer optional." )
85
86
f .BoolVar (& cfg .NormaliseTokens , prefix + "normalise-tokens" , false , "Store tokens in a normalised fashion to reduce allocations." )
86
87
f .DurationVar (& cfg .FinalSleep , prefix + "final-sleep" , 30 * time .Second , "Duration to sleep for before exiting, to ensure metrics are scraped." )
88
+ f .StringVar (& cfg .TokensFilePath , prefix + "tokens-file-path" , "" , "File path where tokens are stored. If empty, tokens are not stored at shutdown and restored at startup." )
87
89
88
90
hostname , err := os .Hostname ()
89
91
if err != nil {
@@ -125,7 +127,7 @@ type Lifecycler struct {
125
127
// back empty. And it changes during lifecycle of ingester.
126
128
stateMtx sync.Mutex
127
129
state IngesterState
128
- tokens [] uint32
130
+ tokens Tokens
129
131
130
132
// Controls the ready-reporting
131
133
readyLock sync.Mutex
@@ -246,18 +248,24 @@ func (i *Lifecycler) ChangeState(ctx context.Context, state IngesterState) error
246
248
return <- err
247
249
}
248
250
249
- func (i * Lifecycler ) getTokens () [] uint32 {
251
+ func (i * Lifecycler ) getTokens () Tokens {
250
252
i .stateMtx .Lock ()
251
253
defer i .stateMtx .Unlock ()
252
254
return i .tokens
253
255
}
254
256
255
- func (i * Lifecycler ) setTokens (tokens [] uint32 ) {
257
+ func (i * Lifecycler ) setTokens (tokens Tokens ) {
256
258
tokensOwned .WithLabelValues (i .RingName ).Set (float64 (len (tokens )))
257
259
258
260
i .stateMtx .Lock ()
259
261
defer i .stateMtx .Unlock ()
262
+
260
263
i .tokens = tokens
264
+ if i .cfg .TokensFilePath != "" {
265
+ if err := i .tokens .StoreToFile (i .cfg .TokensFilePath ); err != nil {
266
+ level .Error (util .Logger ).Log ("msg" , "error storing tokens to disk" , "path" , i .cfg .TokensFilePath , "err" , err )
267
+ }
268
+ }
261
269
}
262
270
263
271
// ClaimTokensFor takes all the tokens for the supplied ingester and assigns them to this ingester.
@@ -270,7 +278,7 @@ func (i *Lifecycler) ClaimTokensFor(ctx context.Context, ingesterID string) erro
270
278
err := make (chan error )
271
279
272
280
i .actorChan <- func () {
273
- var tokens [] uint32
281
+ var tokens Tokens
274
282
275
283
claimTokens := func (in interface {}) (out interface {}, retry bool , err error ) {
276
284
ringDesc , ok := in .(* Desc )
@@ -445,9 +453,22 @@ heartbeatLoop:
445
453
// - add an ingester entry to the ring
446
454
// - copies out our state and tokens if they exist
447
455
func (i * Lifecycler ) initRing (ctx context.Context ) error {
448
- var ringDesc * Desc
456
+ var (
457
+ ringDesc * Desc
458
+ tokensFromFile Tokens
459
+ err error
460
+ )
461
+
462
+ if i .cfg .TokensFilePath != "" {
463
+ tokensFromFile , err = LoadTokensFromFile (i .cfg .TokensFilePath )
464
+ if err != nil {
465
+ level .Error (util .Logger ).Log ("msg" , "error in getting tokens from file" , "err" , err )
466
+ }
467
+ } else {
468
+ level .Info (util .Logger ).Log ("msg" , "not loading tokens from file, tokens file path is empty" )
469
+ }
449
470
450
- err : = i .KVStore .CAS (ctx , ConsulKey , func (in interface {}) (out interface {}, retry bool , err error ) {
471
+ err = i .KVStore .CAS (ctx , ConsulKey , func (in interface {}) (out interface {}, retry bool , err error ) {
451
472
if in == nil {
452
473
ringDesc = NewDesc ()
453
474
} else {
@@ -456,6 +477,17 @@ func (i *Lifecycler) initRing(ctx context.Context) error {
456
477
457
478
ingesterDesc , ok := ringDesc .Ingesters [i .ID ]
458
479
if ! ok {
480
+ // We use the tokens from the file only if it does not exist in the ring yet.
481
+ if len (tokensFromFile ) > 0 {
482
+ level .Info (util .Logger ).Log ("msg" , "adding tokens from file" , "num_tokens" , len (tokensFromFile ))
483
+ if len (tokensFromFile ) >= i .cfg .NumTokens {
484
+ i .setState (ACTIVE )
485
+ }
486
+ ringDesc .AddIngester (i .ID , i .Addr , tokensFromFile , i .GetState (), i .cfg .NormaliseTokens )
487
+ i .setTokens (tokensFromFile )
488
+ return ringDesc , true , nil
489
+ }
490
+
459
491
// Either we are a new ingester, or consul must have restarted
460
492
level .Info (util .Logger ).Log ("msg" , "entry not found in ring, adding with no tokens" )
461
493
ringDesc .AddIngester (i .ID , i .Addr , []uint32 {}, i .GetState (), i .cfg .NormaliseTokens )
@@ -505,7 +537,7 @@ func (i *Lifecycler) verifyTokens(ctx context.Context) bool {
505
537
newTokens := GenerateTokens (needTokens , takenTokens )
506
538
507
539
ringTokens = append (ringTokens , newTokens ... )
508
- sort .Sort (sortableUint32 ( ringTokens ) )
540
+ sort .Sort (ringTokens )
509
541
510
542
ringDesc .AddIngester (i .ID , i .Addr , ringTokens , i .GetState (), i .cfg .NormaliseTokens )
511
543
@@ -527,11 +559,11 @@ func (i *Lifecycler) verifyTokens(ctx context.Context) bool {
527
559
return result
528
560
}
529
561
530
- func (i * Lifecycler ) compareTokens (fromRing [] uint32 ) bool {
531
- sort .Sort (sortableUint32 ( fromRing ) )
562
+ func (i * Lifecycler ) compareTokens (fromRing Tokens ) bool {
563
+ sort .Sort (fromRing )
532
564
533
565
tokens := i .getTokens ()
534
- sort .Sort (sortableUint32 ( tokens ) )
566
+ sort .Sort (tokens )
535
567
536
568
if len (tokens ) != len (fromRing ) {
537
569
return false
@@ -566,9 +598,9 @@ func (i *Lifecycler) autoJoin(ctx context.Context, targetState IngesterState) er
566
598
i .setState (targetState )
567
599
ringDesc .AddIngester (i .ID , i .Addr , newTokens , i .GetState (), i .cfg .NormaliseTokens )
568
600
569
- tokens : = append (myTokens , newTokens ... )
570
- sort .Sort (sortableUint32 ( tokens ) )
571
- i .setTokens (tokens )
601
+ myTokens = append (myTokens , newTokens ... )
602
+ sort .Sort (myTokens )
603
+ i .setTokens (myTokens )
572
604
573
605
return ringDesc , true , nil
574
606
})
0 commit comments