@@ -2,6 +2,7 @@ package storegateway
22
33import (
44 "context"
5+ "errors"
56 "fmt"
67 "strconv"
78 "testing"
@@ -11,7 +12,9 @@ import (
1112 "github.com/oklog/ulid"
1213 "github.com/prometheus/client_golang/prometheus"
1314 "github.com/prometheus/client_golang/prometheus/testutil"
15+ "github.com/prometheus/prometheus/tsdb"
1416 "github.com/stretchr/testify/assert"
17+ "github.com/stretchr/testify/mock"
1518 "github.com/stretchr/testify/require"
1619 "github.com/thanos-io/thanos/pkg/block/metadata"
1720 "github.com/thanos-io/thanos/pkg/extprom"
@@ -272,6 +275,11 @@ func TestDefaultShardingStrategy(t *testing.T) {
272275
273276 for instanceAddr , expectedBlocks := range testData .expectedBlocks {
274277 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+ }
275283 synced := extprom .NewTxGaugeVec (nil , prometheus.GaugeOpts {}, []string {"state" })
276284 synced .WithLabelValues (shardExcludedMeta ).Set (0 )
277285
@@ -657,6 +665,11 @@ func TestShuffleShardingStrategy(t *testing.T) {
657665 // Assert on filter blocks.
658666 for _ , expected := range testData .expectedBlocks {
659667 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+ }
660673 synced := extprom .NewTxGaugeVec (nil , prometheus.GaugeOpts {}, []string {"state" })
661674 synced .WithLabelValues (shardExcludedMeta ).Set (0 )
662675
@@ -693,3 +706,159 @@ type shardingLimitsMock struct {
693706func (m * shardingLimitsMock ) StoreGatewayTenantShardSize (_ string ) float64 {
694707 return m .storeGatewayTenantShardSize
695708}
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