perf: expand gateway capacity and prevent receipt replay
This commit is contained in:
@@ -45,11 +45,20 @@ func (p *connectionPool) tryAcquireConnection() (*connection, func()) {
|
||||
if len(p.conns) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
for i := 0; i < len(p.conns); i++ {
|
||||
index := (p.next + i) % len(p.conns)
|
||||
conn := p.conns[index]
|
||||
bestIndex := -1
|
||||
bestInFlight := int(^uint(0) >> 1)
|
||||
var bestRTT time.Duration
|
||||
for index, conn := range p.conns {
|
||||
inFlight, rtt, usable := conn.capacitySnapshot()
|
||||
if !usable || inFlight > bestInFlight || (inFlight == bestInFlight && bestIndex >= 0 && bestRTT > 0 && rtt >= bestRTT) {
|
||||
continue
|
||||
}
|
||||
bestIndex, bestInFlight, bestRTT = index, inFlight, rtt
|
||||
}
|
||||
if bestIndex >= 0 {
|
||||
conn := p.conns[bestIndex]
|
||||
if conn.tryAcquireWindow() {
|
||||
p.next = (index + 1) % len(p.conns)
|
||||
p.next = (bestIndex + 1) % len(p.conns)
|
||||
return conn, conn.releaseWindow
|
||||
}
|
||||
}
|
||||
@@ -57,8 +66,17 @@ func (p *connectionPool) tryAcquireConnection() (*connection, func()) {
|
||||
}
|
||||
|
||||
func (c *connection) tryAcquireWindow() bool {
|
||||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
if c.window == nil {
|
||||
c.window = make(chan struct{}, defaultWindowSize)
|
||||
c.window = make(chan struct{}, maximumWindowSize)
|
||||
}
|
||||
limit := c.windowLimit
|
||||
if limit < 1 {
|
||||
limit = defaultWindowSize
|
||||
}
|
||||
if c.closed || c.draining || c.client == nil || len(c.window) >= limit {
|
||||
return false
|
||||
}
|
||||
select {
|
||||
case c.window <- struct{}{}:
|
||||
@@ -68,6 +86,37 @@ func (c *connection) tryAcquireWindow() bool {
|
||||
}
|
||||
}
|
||||
|
||||
func (c *connection) capacitySnapshot() (int, time.Duration, bool) {
|
||||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
limit := c.windowLimit
|
||||
if limit < 1 {
|
||||
limit = defaultWindowSize
|
||||
}
|
||||
inFlight := len(c.window)
|
||||
return inFlight, c.lastSubmitRTT, !c.closed && !c.draining && c.client != nil && inFlight < limit && !time.Now().Before(c.cooldownUntil)
|
||||
}
|
||||
|
||||
func (c *connection) markSubmitFailure() {
|
||||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
c.consecutiveFailures++
|
||||
if c.consecutiveFailures >= 3 {
|
||||
seconds := c.config.FailureCooldownSeconds
|
||||
if seconds <= 0 {
|
||||
seconds = 30
|
||||
}
|
||||
c.cooldownUntil = time.Now().Add(time.Duration(seconds) * time.Second)
|
||||
}
|
||||
}
|
||||
|
||||
func (c *connection) markSubmitSuccess() {
|
||||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
c.consecutiveFailures = 0
|
||||
c.cooldownUntil = time.Time{}
|
||||
}
|
||||
|
||||
func (c *connection) releaseWindow() {
|
||||
if c.window == nil {
|
||||
return
|
||||
|
||||
Reference in New Issue
Block a user