Skip to content

Commit bec09a5

Browse files
committed
slight reordering
1 parent 8654d1a commit bec09a5

File tree

4 files changed

+40
-19
lines changed

4 files changed

+40
-19
lines changed

internal/pool/conn.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
// Package pool implements the pool management
12
package pool
23

34
import (
@@ -79,6 +80,7 @@ type Conn struct {
7980
expiresAt time.Time
8081

8182
// maintenanceNotifications upgrade support: relaxed timeouts during migrations/failovers
83+
8284
// Using atomic operations for lock-free access to avoid mutex contention
8385
relaxedReadTimeoutNs atomic.Int64 // time.Duration as nanoseconds
8486
relaxedWriteTimeoutNs atomic.Int64 // time.Duration as nanoseconds
@@ -839,6 +841,8 @@ func (cn *Conn) MaybeHasData() bool {
839841
return false
840842
}
841843

844+
// deadline computes the effective deadline time based on context and timeout.
845+
// It updates the usedAt timestamp to now.
842846
func (cn *Conn) deadline(ctx context.Context, timeout time.Duration) time.Time {
843847
tm := time.Now()
844848
cn.SetUsedAt(tm)

internal/pool/pool.go

Lines changed: 34 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -865,36 +865,53 @@ func (p *ConnPool) Close() error {
865865
}
866866

867867
func (p *ConnPool) isHealthyConn(cn *Conn, now time.Time) bool {
868-
// slight optimization, check expiresAt first.
869-
if cn.expiresAt.Before(now) {
870-
return false
868+
// Performance optimization: check conditions from cheapest to most expensive,
869+
// and from most likely to fail to least likely to fail.
870+
871+
// Only fails if ConnMaxLifetime is set AND connection is old.
872+
// Most pools don't set ConnMaxLifetime, so this rarely fails.
873+
if p.cfg.ConnMaxLifetime > 0 {
874+
if cn.expiresAt.Before(now) {
875+
return false // Connection has exceeded max lifetime
876+
}
871877
}
872878

873-
// Check if connection has exceeded idle timeout
874-
if p.cfg.ConnMaxIdleTime > 0 && now.Sub(cn.UsedAt()) >= p.cfg.ConnMaxIdleTime {
875-
return false
879+
// Most pools set ConnMaxIdleTime, and idle connections are common.
880+
// Checking this first allows us to fail fast without expensive syscalls.
881+
if p.cfg.ConnMaxIdleTime > 0 {
882+
if now.Sub(cn.UsedAt()) >= p.cfg.ConnMaxIdleTime {
883+
return false // Connection has been idle too long
884+
}
876885
}
877886

878-
cn.SetUsedAt(now)
879-
// Check basic connection health
880-
// Use GetNetConn() to safely access netConn and avoid data races
887+
// Only run this if the cheap checks passed.
881888
if err := connCheck(cn.getNetConn()); err != nil {
882889
// If there's unexpected data, it might be push notifications (RESP3)
883-
// However, push notification processing is now handled by the client
884-
// before WithReader to ensure proper context is available to handlers
885890
if p.cfg.PushNotificationsEnabled && err == errUnexpectedRead {
886-
// we know that there is something in the buffer, so peek at the next reply type without
887-
// the potential to block
891+
// Peek at the reply type to check if it's a push notification
888892
if replyType, err := cn.rd.PeekReplyType(); err == nil && replyType == proto.RespPush {
889893
// For RESP3 connections with push notifications, we allow some buffered data
890894
// The client will process these notifications before using the connection
891-
internal.Logger.Printf(context.Background(), "push: conn[%d] has buffered data, likely push notifications - will be processed by client", cn.GetID())
892-
return true // Connection is healthy, client will handle notifications
895+
internal.Logger.Printf(
896+
context.Background(),
897+
"push: conn[%d] has buffered data, likely push notifications - will be processed by client",
898+
cn.GetID(),
899+
)
900+
901+
// Update timestamp for healthy connection
902+
cn.SetUsedAt(now)
903+
904+
// Connection is healthy, client will handle notifications
905+
return true
893906
}
894-
return false // Unexpected data, not push notifications, connection is unhealthy
895-
} else {
907+
// Not a push notification - treat as unhealthy
896908
return false
897909
}
910+
// Connection failed health check
911+
return false
898912
}
913+
914+
// Only update UsedAt if connection is healthy (avoids unnecessary atomic store)
915+
cn.SetUsedAt(now)
899916
return true
900917
}

internal/pool/pubsub.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ type PubSubPool struct {
2424
stats PubSubStats
2525
}
2626

27-
// PubSubPool implements a pool for PubSub connections.
27+
// NewPubSubPool implements a pool for PubSub connections.
2828
// It intentionally does not implement the Pooler interface
2929
func NewPubSubPool(opt *Options, netDialer func(ctx context.Context, network, addr string) (net.Conn, error)) *PubSubPool {
3030
return &PubSubPool{

internal/semaphore.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -159,4 +159,4 @@ func (s *FastSemaphore) Release() {
159159
// Used by tests to check semaphore state.
160160
func (s *FastSemaphore) Len() int32 {
161161
return s.count.Load()
162-
}
162+
}

0 commit comments

Comments
 (0)