@@ -21,15 +21,25 @@ import (
2121 "net"
2222 "os"
2323 "path"
24+ "slices"
2425 "strconv"
2526 "strings"
27+ "sync"
2628
2729 "vitess.io/vitess/go/vt/proto/vttest"
2830
2931 // we use gRPC everywhere, so import the vtgate client.
3032 _ "vitess.io/vitess/go/vt/vtgate/grpcvtgateconn"
3133)
3234
35+ var (
36+ // randomPortsMu provides synchronization for randomPorts().
37+ randomPortsMu sync.Mutex
38+
39+ // usedRandomPorts stores ports that have been used by remotePort().
40+ usedRandomPorts []int
41+ )
42+
3343// Environment is the interface that customizes the global settings for
3444// the test cluster. Usually the same environment settings are shared by
3545// all the LocalCluster instances in a given test suite, with each instance
@@ -235,21 +245,31 @@ func tmpdir(dataroot string) (dir string, err error) {
235245// randomPort gets a random port that is available for a TCP connection.
236246// After we generate a random port, we try to establish tcp connections on it and the next 5 values.
237247// If any of them fail, then we try a different port.
238- func randomPort () int {
248+ func randomPort () (port int ) {
249+ randomPortsMu .Lock ()
250+ defer randomPortsMu .Unlock ()
239251 for {
240- port := int (rand .Int32N (20000 ) + 10000 )
252+ portBase := int (rand .Int32N (20000 ) + 10000 )
241253 portInUse := false
254+ portRange := make ([]int , 0 , 6 )
242255 for i := 0 ; i < 6 ; i ++ {
243- ln , err := net .Listen ("tcp" , net .JoinHostPort ("127.0.0.1" , strconv .Itoa (port + i )))
256+ port = portBase + i
257+ if slices .Contains (usedRandomPorts , port ) {
258+ portInUse = true
259+ break
260+ }
261+ ln , err := net .Listen ("tcp" , net .JoinHostPort ("127.0.0.1" , strconv .Itoa (port )))
244262 if err != nil {
245263 portInUse = true
246264 break
247265 }
266+ portRange = append (portRange , port )
248267 ln .Close ()
249268 }
250269 if portInUse {
251270 continue
252271 }
272+ usedRandomPorts = append (usedRandomPorts , portRange ... )
253273 return port
254274 }
255275}
0 commit comments