Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 12 additions & 15 deletions internal/connmgr/connmanager.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// Copyright (c) 2016 The btcsuite developers
// Copyright (c) 2017-2024 The Decred developers
// Copyright (c) 2017-2026 The Decred developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.

Expand Down Expand Up @@ -56,13 +56,11 @@ const (
// ConnReq is the connection request to a network address. If permanent, the
// connection will be retried on disconnection.
type ConnReq struct {
// The following variables must only be used atomically.
//
// id is the unique identifier for this connection request.
//
id atomic.Uint64

// state is the current connection state for this connection request.
id uint64
state uint32
state atomic.Uint32

// The following fields are owned by the connection handler and must not
// be accessed outside of it.
Expand All @@ -87,17 +85,17 @@ type ConnReq struct {

// updateState updates the state of the connection request.
func (c *ConnReq) updateState(state ConnState) {
atomic.StoreUint32(&c.state, uint32(state))
c.state.Store(uint32(state))
}

// ID returns a unique identifier for the connection request.
func (c *ConnReq) ID() uint64 {
return atomic.LoadUint64(&c.id)
return c.id.Load()
}

// State is the connection state of the requested connection.
func (c *ConnReq) State() ConnState {
return ConnState(atomic.LoadUint32(&c.state))
return ConnState(c.state.Load())
}

// String returns a human-readable string for the connection request.
Expand Down Expand Up @@ -209,11 +207,9 @@ type handleForEachConnReq struct {

// ConnManager provides a manager to handle network connections.
type ConnManager struct {
// The following variables must only be used atomically.
//
// connReqCount is the number of connection requests that have been made and
// is primarily used to assign unique connection request IDs.
connReqCount uint64
connReqCount atomic.Uint64

// assignIDMtx synchronizes the assignment of an ID to a connection request
// with overall connection request count above.
Expand Down Expand Up @@ -469,7 +465,8 @@ func (cm *ConnManager) newConnReq(ctx context.Context) {
return
}

c := &ConnReq{id: atomic.AddUint64(&cm.connReqCount, 1)}
c := &ConnReq{}
c.id.Store(cm.connReqCount.Add(1))

// Submit a request of a pending connection attempt to the connection
// manager. By registering the id before the connection is even
Expand Down Expand Up @@ -547,7 +544,7 @@ func (cm *ConnManager) Connect(ctx context.Context, c *ConnReq) {
var doRegisterPending bool
cm.assignIDMtx.Lock()
if c.ID() == 0 {
atomic.StoreUint64(&c.id, atomic.AddUint64(&cm.connReqCount, 1))
c.id.Store(cm.connReqCount.Add(1))
doRegisterPending = true
}
cm.assignIDMtx.Unlock()
Expand Down Expand Up @@ -718,7 +715,7 @@ func (cm *ConnManager) Run(ctx context.Context) {
// Start enough outbound connections to reach the target number when not
// in manual connect mode.
if cm.cfg.GetNewAddress != nil {
curConnReqCount := atomic.LoadUint64(&cm.connReqCount)
curConnReqCount := cm.connReqCount.Load()
for i := curConnReqCount; i < uint64(cm.cfg.TargetOutbound); i++ {
go cm.newConnReq(ctx)
}
Expand Down
12 changes: 6 additions & 6 deletions internal/connmgr/connmanager_test.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// Copyright (c) 2016 The btcsuite developers
// Copyright (c) 2019-2024 The Decred developers
// Copyright (c) 2019-2026 The Decred developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.

Expand Down Expand Up @@ -405,11 +405,11 @@ func TestNetworkFailure(t *testing.T) {
var closeOnce sync.Once
const targetOutbound = 5
const retryTimeout = time.Millisecond * 5
var dials uint32
var dials atomic.Uint32
reachedMaxFailedAttempts := make(chan struct{})
connMgrDone := make(chan struct{})
errDialer := func(ctx context.Context, network, addr string) (net.Conn, error) {
totalDials := atomic.AddUint32(&dials, 1)
totalDials := dials.Add(1)
if totalDials >= maxFailedAttempts {
closeOnce.Do(func() { close(reachedMaxFailedAttempts) })
<-connMgrDone
Expand Down Expand Up @@ -447,7 +447,7 @@ func TestNetworkFailure(t *testing.T) {
// Ensure the number of dial attempts does not exceed the max number of
// failed attempts plus the number of potential retries during the
// additional waiting period.
gotDials := atomic.LoadUint32(&dials)
gotDials := dials.Load()
wantMaxDials := uint32(maxFailedAttempts + targetOutbound)
if gotDials > wantMaxDials {
t.Fatalf("unexpected number of dials - got %v, want <= %v", gotDials,
Expand All @@ -468,11 +468,11 @@ func TestMultipleFailedConns(t *testing.T) {
}()

const targetFailed = 5
var dials uint32
var dials atomic.Uint32
var closeOnce sync.Once
hitTargetFailed := make(chan struct{})
errDialer := func(ctx context.Context, network, addr string) (net.Conn, error) {
totalDials := atomic.AddUint32(&dials, 1)
totalDials := dials.Add(1)
if totalDials >= targetFailed {
closeOnce.Do(func() { close(hitTargetFailed) })
}
Expand Down