mapper/batcher: replace connected map with per-node disconnectedAt
The Batcher's connected field (*xsync.Map[types.NodeID, *time.Time])
encoded three states via pointer semantics:
- nil value: node is connected
- non-nil time: node disconnected at that timestamp
- key missing: node was never seen
This was error-prone (nil meaning 'connected' inverts Go idioms),
redundant with b.nodes + hasActiveConnections(), and required keeping
two parallel maps in sync. It also contained a bug in RemoveNode where
new(time.Now()) was used instead of &now, producing a zero time.
Replace the separate connected map with a disconnectedAt field on
multiChannelNodeConn (atomic.Pointer[time.Time]), tracked directly
on the object that already manages the node's connections.
Changes:
- Add disconnectedAt field and helpers (markConnected, markDisconnected,
isConnected, offlineDuration) to multiChannelNodeConn
- Remove the connected field from Batcher
- Simplify IsConnected from two map lookups to one
- Simplify ConnectedMap and Debug from two-map iteration to one
- Rewrite cleanupOfflineNodes to scan b.nodes directly
- Remove the markDisconnectedIfNoConns helper
- Update all tests and benchmarks
Fixes #3141
This commit is contained in:
parent
60317064fd
commit
87b8507ac9
6 changed files with 148 additions and 191 deletions
|
|
@ -52,6 +52,12 @@ type multiChannelNodeConn struct {
|
|||
closeOnce sync.Once
|
||||
updateCount atomic.Int64
|
||||
|
||||
// disconnectedAt records when the last connection was removed.
|
||||
// nil means the node is considered connected (or newly created);
|
||||
// non-nil means the node disconnected at the stored timestamp.
|
||||
// Used by cleanupOfflineNodes to evict stale entries.
|
||||
disconnectedAt atomic.Pointer[time.Time]
|
||||
|
||||
// lastSentPeers tracks which peers were last sent to this node.
|
||||
// This enables computing diffs for policy changes instead of sending
|
||||
// full peer lists (which clients interpret as "no change" when empty).
|
||||
|
|
@ -162,6 +168,41 @@ func (mc *multiChannelNodeConn) getActiveConnectionCount() int {
|
|||
return len(mc.connections)
|
||||
}
|
||||
|
||||
// markConnected clears the disconnect timestamp, indicating the node
|
||||
// has an active connection.
|
||||
func (mc *multiChannelNodeConn) markConnected() {
|
||||
mc.disconnectedAt.Store(nil)
|
||||
}
|
||||
|
||||
// markDisconnected records the current time as the moment the node
|
||||
// lost its last connection. Used by cleanupOfflineNodes to determine
|
||||
// how long the node has been offline.
|
||||
func (mc *multiChannelNodeConn) markDisconnected() {
|
||||
now := time.Now()
|
||||
mc.disconnectedAt.Store(&now)
|
||||
}
|
||||
|
||||
// isConnected returns true if the node has active connections or has
|
||||
// not been marked as disconnected.
|
||||
func (mc *multiChannelNodeConn) isConnected() bool {
|
||||
if mc.hasActiveConnections() {
|
||||
return true
|
||||
}
|
||||
|
||||
return mc.disconnectedAt.Load() == nil
|
||||
}
|
||||
|
||||
// offlineDuration returns how long the node has been disconnected.
|
||||
// Returns 0 if the node is connected or has never been marked as disconnected.
|
||||
func (mc *multiChannelNodeConn) offlineDuration() time.Duration {
|
||||
t := mc.disconnectedAt.Load()
|
||||
if t == nil {
|
||||
return 0
|
||||
}
|
||||
|
||||
return time.Since(*t)
|
||||
}
|
||||
|
||||
// appendPending appends changes to this node's pending change list.
|
||||
// Thread-safe via pendingMu; does not contend with the connection mutex.
|
||||
func (mc *multiChannelNodeConn) appendPending(changes ...change.Change) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue