7
7
"net"
8
8
"strconv"
9
9
"sync"
10
+ "testing"
10
11
"time"
11
12
12
13
. "github.com/onsi/ginkgo"
@@ -123,15 +124,15 @@ var _ = Describe("Redis Ring", func() {
123
124
})
124
125
Expect (ring .Len (), 1 )
125
126
gotShard := ring .ShardByName ("ringShardOne" )
126
- Expect (gotShard ).To (Equal (wantShard ))
127
+ Expect (gotShard ).To (BeIdenticalTo (wantShard ))
127
128
128
129
ring .SetAddrs (map [string ]string {
129
130
"ringShardOne" : ":" + ringShard1Port ,
130
131
"ringShardTwo" : ":" + ringShard2Port ,
131
132
})
132
133
Expect (ring .Len (), 2 )
133
134
gotShard = ring .ShardByName ("ringShardOne" )
134
- Expect (gotShard ).To (Equal (wantShard ))
135
+ Expect (gotShard ).To (BeIdenticalTo (wantShard ))
135
136
})
136
137
137
138
It ("uses 3 shards after setting it to 3 shards" , func () {
@@ -155,8 +156,8 @@ var _ = Describe("Redis Ring", func() {
155
156
gotShard1 := ring .ShardByName (shardName1 )
156
157
gotShard2 := ring .ShardByName (shardName2 )
157
158
gotShard3 := ring .ShardByName (shardName3 )
158
- Expect (gotShard1 ).To (Equal (wantShard1 ))
159
- Expect (gotShard2 ).To (Equal (wantShard2 ))
159
+ Expect (gotShard1 ).To (BeIdenticalTo (wantShard1 ))
160
+ Expect (gotShard2 ).To (BeIdenticalTo (wantShard2 ))
160
161
Expect (gotShard3 ).ToNot (BeNil ())
161
162
162
163
ring .SetAddrs (map [string ]string {
@@ -167,8 +168,8 @@ var _ = Describe("Redis Ring", func() {
167
168
gotShard1 = ring .ShardByName (shardName1 )
168
169
gotShard2 = ring .ShardByName (shardName2 )
169
170
gotShard3 = ring .ShardByName (shardName3 )
170
- Expect (gotShard1 ).To (Equal (wantShard1 ))
171
- Expect (gotShard2 ).To (Equal (wantShard2 ))
171
+ Expect (gotShard1 ).To (BeIdenticalTo (wantShard1 ))
172
+ Expect (gotShard2 ).To (BeIdenticalTo (wantShard2 ))
172
173
Expect (gotShard3 ).To (BeNil ())
173
174
})
174
175
})
@@ -739,3 +740,89 @@ var _ = Describe("Ring Tx timeout", func() {
739
740
testTimeout ()
740
741
})
741
742
})
743
+
744
+ func TestRingSetAddrsContention (t * testing.T ) {
745
+ const (
746
+ ringShard1Name = "ringShardOne"
747
+ ringShard2Name = "ringShardTwo"
748
+ )
749
+
750
+ for _ , port := range []string {ringShard1Port , ringShard2Port } {
751
+ if _ , err := startRedis (port ); err != nil {
752
+ t .Fatal (err )
753
+ }
754
+ }
755
+
756
+ t .Cleanup (func () {
757
+ for _ , p := range processes {
758
+ if err := p .Close (); err != nil {
759
+ t .Errorf ("Failed to stop redis process: %v" , err )
760
+ }
761
+ }
762
+ processes = nil
763
+ })
764
+
765
+ ring := redis .NewRing (& redis.RingOptions {
766
+ Addrs : map [string ]string {
767
+ "ringShardOne" : ":" + ringShard1Port ,
768
+ },
769
+ NewClient : func (opt * redis.Options ) * redis.Client {
770
+ // Simulate slow shard creation
771
+ time .Sleep (100 * time .Millisecond )
772
+ return redis .NewClient (opt )
773
+ },
774
+ })
775
+ defer ring .Close ()
776
+
777
+ if _ , err := ring .Ping (context .Background ()).Result (); err != nil {
778
+ t .Fatal (err )
779
+ }
780
+
781
+ // Continuously update addresses by adding and removing one address
782
+ updatesDone := make (chan struct {})
783
+ defer func () { close (updatesDone ) }()
784
+ go func () {
785
+ ticker := time .NewTicker (10 * time .Millisecond )
786
+ defer ticker .Stop ()
787
+ for i := 0 ; ; i ++ {
788
+ select {
789
+ case <- ticker .C :
790
+ if i % 2 == 0 {
791
+ ring .SetAddrs (map [string ]string {
792
+ ringShard1Name : ":" + ringShard1Port ,
793
+ })
794
+ } else {
795
+ ring .SetAddrs (map [string ]string {
796
+ ringShard1Name : ":" + ringShard1Port ,
797
+ ringShard2Name : ":" + ringShard2Port ,
798
+ })
799
+ }
800
+ case <- updatesDone :
801
+ return
802
+ }
803
+ }
804
+ }()
805
+
806
+ var pings , errClosed int
807
+ timer := time .NewTimer (1 * time .Second )
808
+ for running := true ; running ; pings ++ {
809
+ select {
810
+ case <- timer .C :
811
+ running = false
812
+ default :
813
+ if _ , err := ring .Ping (context .Background ()).Result (); err != nil {
814
+ if err == redis .ErrClosed {
815
+ // The shard client could be closed while ping command is in progress
816
+ errClosed ++
817
+ } else {
818
+ t .Fatal (err )
819
+ }
820
+ }
821
+ }
822
+ }
823
+
824
+ t .Logf ("Number of pings: %d, errClosed: %d" , pings , errClosed )
825
+ if pings < 10_000 {
826
+ t .Errorf ("Expected at least 10k pings, got: %d" , pings )
827
+ }
828
+ }
0 commit comments