77 "net"
88 "strconv"
99 "sync"
10+ "testing"
1011 "time"
1112
1213 . "github.com/onsi/ginkgo"
@@ -123,15 +124,15 @@ var _ = Describe("Redis Ring", func() {
123124 })
124125 Expect (ring .Len (), 1 )
125126 gotShard := ring .ShardByName ("ringShardOne" )
126- Expect (gotShard ).To (Equal (wantShard ))
127+ Expect (gotShard ).To (BeIdenticalTo (wantShard ))
127128
128129 ring .SetAddrs (map [string ]string {
129130 "ringShardOne" : ":" + ringShard1Port ,
130131 "ringShardTwo" : ":" + ringShard2Port ,
131132 })
132133 Expect (ring .Len (), 2 )
133134 gotShard = ring .ShardByName ("ringShardOne" )
134- Expect (gotShard ).To (Equal (wantShard ))
135+ Expect (gotShard ).To (BeIdenticalTo (wantShard ))
135136 })
136137
137138 It ("uses 3 shards after setting it to 3 shards" , func () {
@@ -155,8 +156,8 @@ var _ = Describe("Redis Ring", func() {
155156 gotShard1 := ring .ShardByName (shardName1 )
156157 gotShard2 := ring .ShardByName (shardName2 )
157158 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 ))
160161 Expect (gotShard3 ).ToNot (BeNil ())
161162
162163 ring .SetAddrs (map [string ]string {
@@ -167,8 +168,8 @@ var _ = Describe("Redis Ring", func() {
167168 gotShard1 = ring .ShardByName (shardName1 )
168169 gotShard2 = ring .ShardByName (shardName2 )
169170 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 ))
172173 Expect (gotShard3 ).To (BeNil ())
173174 })
174175 })
@@ -739,3 +740,89 @@ var _ = Describe("Ring Tx timeout", func() {
739740 testTimeout ()
740741 })
741742})
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