This is an automated email from the ASF dual-hosted git repository.
xuetaoli pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/dubbo-go.git
The following commit(s) were added to refs/heads/develop by this push:
new 1af833720 feat: update go vesion to 1.24 and remove the use of
rand.seed (#3046)
1af833720 is described below
commit 1af8337209699ac54f14c9f4bb613e8a69c14368
Author: ian <[email protected]>
AuthorDate: Mon Nov 10 23:11:59 2025 +0800
feat: update go vesion to 1.24 and remove the use of rand.seed (#3046)
* update the go version and gost version
* fix the random.seed in go1.24
---
cluster/loadbalance/p2c/loadbalance.go | 70 ++++++++++++++++++++---------
cluster/loadbalance/p2c/loadbalance_test.go | 44 +++++++++++++-----
go.mod | 2 +-
3 files changed, 83 insertions(+), 33 deletions(-)
diff --git a/cluster/loadbalance/p2c/loadbalance.go
b/cluster/loadbalance/p2c/loadbalance.go
index 04a4ef648..127d75fc1 100644
--- a/cluster/loadbalance/p2c/loadbalance.go
+++ b/cluster/loadbalance/p2c/loadbalance.go
@@ -37,15 +37,10 @@ import (
"dubbo.apache.org/dubbo-go/v3/protocol/base"
)
-var (
- randSeed = func() int64 {
- return time.Now().Unix()
- }
-)
-
func init() {
- rand.Seed(randSeed())
- extension.SetLoadbalance(constant.LoadBalanceKeyP2C, newP2CLoadBalance)
+ extension.SetLoadbalance(constant.LoadBalanceKeyP2C, func()
loadbalance.LoadBalance {
+ return newP2CLoadBalance(nil)
+ })
}
var (
@@ -53,12 +48,54 @@ var (
instance loadbalance.LoadBalance
)
-type p2cLoadBalance struct{}
+// p2cLoadBalance is a load balancer implementation based on the Power of Two
Choices algorithm.
+type p2cLoadBalance struct {
+ // randomPicker is injectable for testing; allows deterministic random
selection.
+ randomPicker randomPicker
+}
+
+// randomPicker is a function type that randomly selects two distinct indices
from a range [0, n).
+// This function type is designed ONLY FOR TEST purposes to inject predictable
values.
+type randomPicker func(n int) (i, j int)
+
+var rndPool = sync.Pool{
+ New: func() any {
+ return rand.New(rand.NewSource(time.Now().Unix()))
+ },
+}
+
+// defaultRnd is the default implementation of randomPicker.
+// It handles edge cases for n <= 2 and ensures two distinct random indices
for n > 2.
+func defaultRnd(n int) (i, j int) {
+ if n <= 1 {
+ return 0, 0
+ }
+ if n == 2 {
+ return 0, 1
+ }
+
+ rnd := rndPool.Get().(*rand.Rand)
+ defer rndPool.Put(rnd)
-func newP2CLoadBalance() loadbalance.LoadBalance {
+ i = rnd.Intn(n) // NOSONAR
+ j = rnd.Intn(n) // NOSONAR
+ for i == j {
+ j = rnd.Intn(n) // NOSONAR
+ }
+ return i, j
+}
+
+// newP2CLoadBalance creates or returns the singleton P2C load balancer.
+// Uses the provided randomPicker if non-nil; otherwise defaults to defaultRnd.
+// randomPicker parameter is designed ONLY FOR TEST purposes.
+// Thread-safe via sync.Once.
+func newP2CLoadBalance(r randomPicker) loadbalance.LoadBalance {
+ if r == nil {
+ r = defaultRnd
+ }
if instance == nil {
once.Do(func() {
- instance = &p2cLoadBalance{}
+ instance = &p2cLoadBalance{randomPicker: r}
})
}
return instance
@@ -75,16 +112,7 @@ func (l *p2cLoadBalance) Select(invokers []base.Invoker,
invocation base.Invocat
// The local metrics is available only for the earlier version.
m := metrics.LocalMetrics
// picks two nodes randomly
- var i, j int
- if len(invokers) == 2 {
- i, j = 0, 1
- } else {
- i = rand.Intn(len(invokers))
- j = i
- for i == j {
- j = rand.Intn(len(invokers))
- }
- }
+ i, j := l.randomPicker(len(invokers))
logger.Debugf("[P2C select] Two invokers were selected, invoker[%d]:
%s, invoker[%d]: %s.",
i, invokers[i], j, invokers[j])
diff --git a/cluster/loadbalance/p2c/loadbalance_test.go
b/cluster/loadbalance/p2c/loadbalance_test.go
index 489e0a66e..e8ac720b1 100644
--- a/cluster/loadbalance/p2c/loadbalance_test.go
+++ b/cluster/loadbalance/p2c/loadbalance_test.go
@@ -18,7 +18,6 @@
package p2c
import (
- "math/rand"
"testing"
)
@@ -35,21 +34,48 @@ import (
protoinvoc "dubbo.apache.org/dubbo-go/v3/protocol/invocation"
)
+func TestDefaultRnd(t *testing.T) {
+ t.Run("n <= 1", func(t *testing.T) {
+ i, j := defaultRnd(1)
+ assert.Equal(t, 0, i)
+ assert.Equal(t, 0, j)
+ })
+
+ t.Run("n == 2", func(t *testing.T) {
+ i, j := defaultRnd(2)
+ assert.Equal(t, 0, i)
+ assert.Equal(t, 1, j)
+ })
+
+ t.Run("n > 2", func(t *testing.T) {
+ n := 5
+ i, j := defaultRnd(n)
+ assert.True(t, i >= 0 && i < n)
+ assert.True(t, j >= 0 && j < n)
+ assert.NotEqual(t, i, j)
+ })
+}
+
func TestLoadBalance(t *testing.T) {
- lb := newP2CLoadBalance()
+ // Create P2C load balancer with deterministic randomPicker for
repeatable tests.
+ // Always returns fixed indices (0,1) except when n <= 1.
+ lb := newP2CLoadBalance(func(n int) (i, j int) {
+ if n <= 1 {
+ return 0, 0
+ }
+ if n == 2 {
+ return 0, 1
+ }
+ return 0, 1
+ })
invocation := protoinvoc.NewRPCInvocation("TestMethod", []any{}, nil)
- randSeed := func() int64 {
- return 0
- }
t.Run("no invokers", func(t *testing.T) {
- rand.Seed(randSeed())
ivk := lb.Select([]base.Invoker{}, invocation)
assert.Nil(t, ivk)
})
t.Run("one invoker", func(t *testing.T) {
- rand.Seed(randSeed())
url0, _ :=
common.NewURL("dubbo://192.168.1.0:20000/com.ikurento.user.UserProvider")
ivkArr := []base.Invoker{
@@ -60,7 +86,6 @@ func TestLoadBalance(t *testing.T) {
})
t.Run("two invokers", func(t *testing.T) {
- rand.Seed(randSeed())
ctrl := gomock.NewController(t)
defer ctrl.Finish()
@@ -90,7 +115,6 @@ func TestLoadBalance(t *testing.T) {
})
t.Run("multiple invokers", func(t *testing.T) {
- rand.Seed(randSeed())
ctrl := gomock.NewController(t)
defer ctrl.Finish()
@@ -122,7 +146,6 @@ func TestLoadBalance(t *testing.T) {
})
t.Run("metrics i not found", func(t *testing.T) {
- rand.Seed(randSeed())
ctrl := gomock.NewController(t)
defer ctrl.Finish()
@@ -150,7 +173,6 @@ func TestLoadBalance(t *testing.T) {
})
t.Run("metrics j not found", func(t *testing.T) {
- rand.Seed(randSeed())
ctrl := gomock.NewController(t)
defer ctrl.Finish()
diff --git a/go.mod b/go.mod
index 724ec6c7a..c1433902c 100644
--- a/go.mod
+++ b/go.mod
@@ -1,6 +1,6 @@
module dubbo.apache.org/dubbo-go/v3
-go 1.23
+go 1.24.0
require (
github.com/RoaringBitmap/roaring v1.2.3