@@ -2523,6 +2523,111 @@ func TestRing_ShuffleShardWithLookback(t *testing.T) {
25232523 }
25242524}
25252525
2526+ func TestRing_ShuffleShardWithReadOnlyIngesters (t * testing.T ) {
2527+ g := NewRandomTokenGenerator ()
2528+
2529+ const (
2530+ userID = "user-1"
2531+ )
2532+
2533+ tests := map [string ]struct {
2534+ ringInstances map [string ]InstanceDesc
2535+ ringReplicationFactor int
2536+ shardSize int
2537+ expectedSize int
2538+ op Operation
2539+ expectedToBePresent []string
2540+ }{
2541+ "single zone, shard size = 1, default scenario" : {
2542+ ringInstances : map [string ]InstanceDesc {
2543+ "instance-1" : {Addr : "127.0.0.1" , Zone : "zone-a" , State : ACTIVE , Tokens : g .GenerateTokens (NewDesc (), "instance-1" , "zone-a" , 128 , true )},
2544+ "instance-2" : {Addr : "127.0.0.2" , Zone : "zone-a" , State : ACTIVE , Tokens : g .GenerateTokens (NewDesc (), "instance-2" , "zone-a" , 128 , true )},
2545+ },
2546+ ringReplicationFactor : 1 ,
2547+ shardSize : 1 ,
2548+ expectedSize : 1 ,
2549+ },
2550+ "single zone, shard size = 1, not filter ReadOnly" : {
2551+ ringInstances : map [string ]InstanceDesc {
2552+ "instance-1" : {Addr : "127.0.0.1" , Zone : "zone-a" , State : ACTIVE , Tokens : g .GenerateTokens (NewDesc (), "instance-1" , "zone-a" , 128 , true )},
2553+ "instance-2" : {Addr : "127.0.0.2" , Zone : "zone-a" , State : READONLY , Tokens : g .GenerateTokens (NewDesc (), "instance-2" , "zone-a" , 128 , true )},
2554+ },
2555+ ringReplicationFactor : 1 ,
2556+ shardSize : 2 ,
2557+ expectedSize : 2 ,
2558+ },
2559+ "single zone, shard size = 4, do not filter other states" : {
2560+ ringInstances : map [string ]InstanceDesc {
2561+ "instance-1" : {Addr : "127.0.0.1" , Zone : "zone-a" , State : ACTIVE , Tokens : g .GenerateTokens (NewDesc (), "instance-1" , "zone-a" , 128 , true )},
2562+ "instance-2" : {Addr : "127.0.0.2" , Zone : "zone-a" , State : JOINING , Tokens : g .GenerateTokens (NewDesc (), "instance-2" , "zone-a" , 128 , true )},
2563+ "instance-3" : {Addr : "127.0.0.3" , Zone : "zone-a" , State : LEAVING , Tokens : g .GenerateTokens (NewDesc (), "instance-3" , "zone-a" , 128 , true )},
2564+ "instance-4" : {Addr : "127.0.0.4" , Zone : "zone-a" , State : PENDING , Tokens : g .GenerateTokens (NewDesc (), "instance-4" , "zone-a" , 128 , true )},
2565+ },
2566+ ringReplicationFactor : 1 ,
2567+ shardSize : 4 ,
2568+ expectedSize : 4 ,
2569+ },
2570+ "single zone, shard size = 4, extend on readOnly" : {
2571+ ringInstances : map [string ]InstanceDesc {
2572+ "instance-1" : {Addr : "127.0.0.1" , Zone : "zone-a" , State : ACTIVE , Tokens : []uint32 {2 }},
2573+ "instance-2" : {Addr : "127.0.0.2" , Zone : "zone-a" , State : ACTIVE , Tokens : []uint32 {4 }},
2574+ "instance-3" : {Addr : "127.0.0.3" , Zone : "zone-a" , State : ACTIVE , Tokens : []uint32 {6 }},
2575+ "instance-4" : {Addr : "127.0.0.4" , Zone : "zone-a" , State : READONLY , Tokens : []uint32 {1 , 3 , 5 }},
2576+ },
2577+ ringReplicationFactor : 1 ,
2578+ shardSize : 2 ,
2579+ expectedSize : 3 ,
2580+ expectedToBePresent : []string {"instance-4" },
2581+ },
2582+ "rf = 3, shard size = 4, extend readOnly from different zones" : {
2583+ ringInstances : map [string ]InstanceDesc {
2584+ "instance-1" : {Addr : "127.0.0.1" , Zone : "zone-a" , State : ACTIVE , Tokens : []uint32 {2 }},
2585+ "instance-2" : {Addr : "127.0.0.2" , Zone : "zone-b" , State : ACTIVE , Tokens : []uint32 {12 }},
2586+ "instance-3" : {Addr : "127.0.0.3" , Zone : "zone-c" , State : ACTIVE , Tokens : []uint32 {22 }},
2587+ "instance-4" : {Addr : "127.0.0.4" , Zone : "zone-a" , State : ACTIVE , Tokens : []uint32 {4 }},
2588+ "instance-5" : {Addr : "127.0.0.5" , Zone : "zone-b" , State : ACTIVE , Tokens : []uint32 {14 }},
2589+ "instance-6" : {Addr : "127.0.0.6" , Zone : "zone-c" , State : ACTIVE , Tokens : []uint32 {24 }},
2590+ "instance-7" : {Addr : "127.0.0.7" , Zone : "zone-a" , State : READONLY , Tokens : []uint32 {1 , 3 }},
2591+ "instance-8" : {Addr : "127.0.0.8" , Zone : "zone-b" , State : READONLY , Tokens : []uint32 {11 , 13 }},
2592+ "instance-9" : {Addr : "127.0.0.9" , Zone : "zone-c" , State : READONLY , Tokens : []uint32 {21 , 23 }},
2593+ },
2594+ ringReplicationFactor : 3 ,
2595+ shardSize : 6 ,
2596+ expectedSize : 9 ,
2597+ expectedToBePresent : []string {"instance-7" , "instance-8" , "instance-9" },
2598+ },
2599+ }
2600+
2601+ for testName , testData := range tests {
2602+ t .Run (testName , func (t * testing.T ) {
2603+ // Init the ring.
2604+ ringDesc := & Desc {Ingesters : testData .ringInstances }
2605+ for id , instance := range ringDesc .Ingesters {
2606+ ringDesc .Ingesters [id ] = instance
2607+ }
2608+
2609+ ring := Ring {
2610+ cfg : Config {
2611+ ReplicationFactor : testData .ringReplicationFactor ,
2612+ },
2613+ ringDesc : ringDesc ,
2614+ ringTokens : ringDesc .GetTokens (),
2615+ ringTokensByZone : ringDesc .getTokensByZone (),
2616+ ringInstanceByToken : ringDesc .getTokensInfo (),
2617+ ringZones : getZones (ringDesc .getTokensByZone ()),
2618+ strategy : NewDefaultReplicationStrategy (),
2619+ KVClient : & MockClient {},
2620+ }
2621+
2622+ shardRing := ring .ShuffleShard (userID , testData .shardSize )
2623+ assert .Equal (t , testData .expectedSize , shardRing .InstancesCount ())
2624+ for _ , expectedInstance := range testData .expectedToBePresent {
2625+ assert .True (t , shardRing .HasInstance (expectedInstance ))
2626+ }
2627+ })
2628+ }
2629+ }
2630+
25262631func TestRing_ShuffleShardWithLookback_CorrectnessWithFuzzy (t * testing.T ) {
25272632 // The goal of this test is NOT to ensure that the minimum required number of instances
25282633 // are returned at any given time, BUT at least all required instances are returned.
0 commit comments