@@ -2,6 +2,7 @@ package storegateway
2
2
3
3
import (
4
4
"context"
5
+ "errors"
5
6
"fmt"
6
7
"strconv"
7
8
"testing"
@@ -11,7 +12,9 @@ import (
11
12
"github.com/oklog/ulid"
12
13
"github.com/prometheus/client_golang/prometheus"
13
14
"github.com/prometheus/client_golang/prometheus/testutil"
15
+ "github.com/prometheus/prometheus/tsdb"
14
16
"github.com/stretchr/testify/assert"
17
+ "github.com/stretchr/testify/mock"
15
18
"github.com/stretchr/testify/require"
16
19
"github.com/thanos-io/thanos/pkg/block/metadata"
17
20
"github.com/thanos-io/thanos/pkg/extprom"
@@ -272,6 +275,11 @@ func TestDefaultShardingStrategy(t *testing.T) {
272
275
273
276
for instanceAddr , expectedBlocks := range testData .expectedBlocks {
274
277
filter := NewDefaultShardingStrategy (r , instanceAddr , log .NewNopLogger (), nil )
278
+ for _ , block := range expectedBlocks {
279
+ owned , err := filter .OwnBlock ("user-1" , metadata.Meta {BlockMeta : tsdb.BlockMeta {ULID : block }})
280
+ require .NoError (t , err )
281
+ require .True (t , owned )
282
+ }
275
283
synced := extprom .NewTxGaugeVec (nil , prometheus.GaugeOpts {}, []string {"state" })
276
284
synced .WithLabelValues (shardExcludedMeta ).Set (0 )
277
285
@@ -657,6 +665,11 @@ func TestShuffleShardingStrategy(t *testing.T) {
657
665
// Assert on filter blocks.
658
666
for _ , expected := range testData .expectedBlocks {
659
667
filter := NewShuffleShardingStrategy (r , expected .instanceID , expected .instanceAddr , testData .limits , log .NewNopLogger (), allowedTenants , zoneStableShuffleSharding ) //nolint:govet
668
+ for _ , block := range expected .blocks {
669
+ owned , err := filter .OwnBlock (userID , metadata.Meta {BlockMeta : tsdb.BlockMeta {ULID : block }})
670
+ require .NoError (t , err )
671
+ require .True (t , owned )
672
+ }
660
673
synced := extprom .NewTxGaugeVec (nil , prometheus.GaugeOpts {}, []string {"state" })
661
674
synced .WithLabelValues (shardExcludedMeta ).Set (0 )
662
675
@@ -693,3 +706,159 @@ type shardingLimitsMock struct {
693
706
func (m * shardingLimitsMock ) StoreGatewayTenantShardSize (_ string ) float64 {
694
707
return m .storeGatewayTenantShardSize
695
708
}
709
+
710
+ func TestDefaultShardingStrategy_OwnBlock (t * testing.T ) {
711
+ t .Parallel ()
712
+ // The following block IDs have been picked to have increasing hash values
713
+ // in order to simplify the tests.
714
+ block1 := ulid .MustNew (1 , nil ) // hash: 283204220
715
+ block2 := ulid .MustNew (2 , nil )
716
+ block1Hash := cortex_tsdb .HashBlockID (block1 )
717
+ registeredAt := time .Now ()
718
+ block2Hash := cortex_tsdb .HashBlockID (block2 )
719
+
720
+ ctx := context .Background ()
721
+ store , closer := consul .NewInMemoryClient (ring .GetCodec (), log .NewNopLogger (), nil )
722
+ t .Cleanup (func () { assert .NoError (t , closer .Close ()) })
723
+
724
+ // Initialize the ring state.
725
+ require .NoError (t , store .CAS (ctx , "test" , func (in interface {}) (interface {}, bool , error ) {
726
+ d := ring .NewDesc ()
727
+ d .AddIngester ("instance-1" , "127.0.0.1" , "zone-a" , []uint32 {block1Hash + 1 }, ring .ACTIVE , registeredAt )
728
+ d .AddIngester ("instance-2" , "127.0.0.2" , "zone-b" , []uint32 {block2Hash + 1 }, ring .ACTIVE , registeredAt )
729
+ return d , true , nil
730
+ }))
731
+
732
+ cfg := ring.Config {
733
+ ReplicationFactor : 1 ,
734
+ HeartbeatTimeout : time .Minute ,
735
+ ZoneAwarenessEnabled : true ,
736
+ }
737
+
738
+ r , err := ring .NewWithStoreClientAndStrategy (cfg , "test" , "test" , store , ring .NewIgnoreUnhealthyInstancesReplicationStrategy (), nil , nil )
739
+ require .NoError (t , err )
740
+ require .NoError (t , services .StartAndAwaitRunning (ctx , r ))
741
+ defer services .StopAndAwaitTerminated (ctx , r ) //nolint:errcheck
742
+
743
+ // Wait until the ring client has synced.
744
+ require .NoError (t , ring .WaitInstanceState (ctx , r , "instance-1" , ring .ACTIVE ))
745
+ filter := NewDefaultShardingStrategy (r , "127.0.0.1" , log .NewNopLogger (), nil )
746
+ owned , err := filter .OwnBlock ("" , metadata.Meta {BlockMeta : tsdb.BlockMeta {ULID : block1 }})
747
+ require .NoError (t , err )
748
+ require .True (t , owned )
749
+ // Owned by 127.0.0.2
750
+ owned , err = filter .OwnBlock ("" , metadata.Meta {BlockMeta : tsdb.BlockMeta {ULID : block2 }})
751
+ require .NoError (t , err )
752
+ require .False (t , owned )
753
+
754
+ filter2 := NewDefaultShardingStrategy (r , "127.0.0.2" , log .NewNopLogger (), nil )
755
+ owned , err = filter2 .OwnBlock ("" , metadata.Meta {BlockMeta : tsdb.BlockMeta {ULID : block2 }})
756
+ require .NoError (t , err )
757
+ require .True (t , owned )
758
+ }
759
+
760
+ func TestShuffleShardingStrategy_OwnBlock (t * testing.T ) {
761
+ t .Parallel ()
762
+ // The following block IDs have been picked to have increasing hash values
763
+ // in order to simplify the tests.
764
+ block1 := ulid .MustNew (1 , nil ) // hash: 283204220
765
+ block2 := ulid .MustNew (2 , nil )
766
+ block1Hash := cortex_tsdb .HashBlockID (block1 )
767
+ registeredAt := time .Now ()
768
+ block2Hash := cortex_tsdb .HashBlockID (block2 )
769
+
770
+ ctx := context .Background ()
771
+ store , closer := consul .NewInMemoryClient (ring .GetCodec (), log .NewNopLogger (), nil )
772
+ t .Cleanup (func () { assert .NoError (t , closer .Close ()) })
773
+
774
+ // Initialize the ring state.
775
+ require .NoError (t , store .CAS (ctx , "test" , func (in interface {}) (interface {}, bool , error ) {
776
+ d := ring .NewDesc ()
777
+ d .AddIngester ("instance-1" , "127.0.0.1" , "zone-a" , []uint32 {block1Hash + 1 }, ring .ACTIVE , registeredAt )
778
+ d .AddIngester ("instance-2" , "127.0.0.2" , "zone-b" , []uint32 {block2Hash + 1 }, ring .ACTIVE , registeredAt )
779
+ d .AddIngester ("instance-3" , "127.0.0.3" , "zone-c" , []uint32 {block2Hash + 2 }, ring .ACTIVE , registeredAt )
780
+ return d , true , nil
781
+ }))
782
+
783
+ cfg := ring.Config {
784
+ ReplicationFactor : 1 ,
785
+ HeartbeatTimeout : time .Minute ,
786
+ ZoneAwarenessEnabled : true ,
787
+ }
788
+ limits := & shardingLimitsMock {storeGatewayTenantShardSize : 2 }
789
+
790
+ r , err := ring .NewWithStoreClientAndStrategy (cfg , "test" , "test" , store , ring .NewIgnoreUnhealthyInstancesReplicationStrategy (), nil , nil )
791
+ require .NoError (t , err )
792
+ require .NoError (t , services .StartAndAwaitRunning (ctx , r ))
793
+ defer services .StopAndAwaitTerminated (ctx , r ) //nolint:errcheck
794
+
795
+ // Wait until the ring client has synced.
796
+ require .NoError (t , ring .WaitInstanceState (ctx , r , "instance-1" , ring .ACTIVE ))
797
+ filter := NewShuffleShardingStrategy (r , "instance-1" , "127.0.0.1" , limits , log .NewNopLogger (), nil , true )
798
+ filter2 := NewShuffleShardingStrategy (r , "instance-2" , "127.0.0.2" , limits , log .NewNopLogger (), nil , true )
799
+
800
+ owned , err := filter .OwnBlock ("user-1" , metadata.Meta {BlockMeta : tsdb.BlockMeta {ULID : block1 }})
801
+ require .NoError (t , err )
802
+ require .True (t , owned )
803
+ // Owned by 127.0.0.2
804
+ owned , err = filter .OwnBlock ("user-1" , metadata.Meta {BlockMeta : tsdb.BlockMeta {ULID : block2 }})
805
+ require .NoError (t , err )
806
+ require .False (t , owned )
807
+
808
+ owned , err = filter2 .OwnBlock ("user-1" , metadata.Meta {BlockMeta : tsdb.BlockMeta {ULID : block2 }})
809
+ require .NoError (t , err )
810
+ require .True (t , owned )
811
+ }
812
+
813
+ func TestShardingBlockLifecycleCallbackAdapter (t * testing.T ) {
814
+ userID := "user-1"
815
+ logger := log .NewNopLogger ()
816
+ block := ulid .MustNew (1 , nil )
817
+ meta := metadata.Meta {BlockMeta : tsdb.BlockMeta {ULID : block }}
818
+
819
+ for _ , tc := range []struct {
820
+ name string
821
+ shardingStrategy func () ShardingStrategy
822
+ expectErr bool
823
+ }{
824
+ {
825
+ name : "own block" ,
826
+ shardingStrategy : func () ShardingStrategy {
827
+ s := & mockShardingStrategy {}
828
+ s .On ("OwnBlock" , mock .Anything , mock .Anything ).Return (true , nil )
829
+ return s
830
+ },
831
+ },
832
+ {
833
+ name : "own block has error, still own block" ,
834
+ shardingStrategy : func () ShardingStrategy {
835
+ s := & mockShardingStrategy {}
836
+ s .On ("OwnBlock" , mock .Anything , mock .Anything ).Return (false , errors .New ("some error" ))
837
+ return s
838
+ },
839
+ },
840
+ {
841
+ name : "not own block" ,
842
+ shardingStrategy : func () ShardingStrategy {
843
+ s := & mockShardingStrategy {}
844
+ s .On ("OwnBlock" , mock .Anything , mock .Anything ).Return (false , nil )
845
+ return s
846
+ },
847
+ expectErr : true ,
848
+ },
849
+ } {
850
+ t .Run (tc .name , func (t * testing.T ) {
851
+ a := & shardingBlockLifecycleCallbackAdapter {
852
+ userID : userID ,
853
+ logger : logger ,
854
+ strategy : tc .shardingStrategy (),
855
+ }
856
+ err := a .PreAdd (meta )
857
+ if tc .expectErr {
858
+ require .Error (t , err )
859
+ } else {
860
+ require .NoError (t , err )
861
+ }
862
+ })
863
+ }
864
+ }
0 commit comments