Close memory holes, adjust tests
This commit is contained in:
@@ -546,6 +546,10 @@ func ensureSlotConnected(s *UserMasterSession, slotIdx int, background bool, cli
|
||||
IsBound: isBound,
|
||||
MaxBufferSize: maxBuf,
|
||||
}
|
||||
if GlobalConfig != nil {
|
||||
slot.AutoHoldDiscardLimit = GlobalConfig.Server.AutoHoldDiscardLimit
|
||||
slot.AutoHoldBurstLimit = GlobalConfig.Server.AutoHoldBurstLimit
|
||||
}
|
||||
s.Slots[slotIdx] = slot
|
||||
go upstreamReader(s, slot, slotIdx)
|
||||
return slot
|
||||
@@ -575,8 +579,7 @@ func connectOrResumeSlot(s *UserMasterSession, slotIdx int, clientConn net.Conn)
|
||||
}()
|
||||
|
||||
slot.Mu.Lock()
|
||||
slot.ScreenChanged = false
|
||||
slot.IsHeld = false
|
||||
slot.resetHoldAndLoopCountersLocked()
|
||||
if len(slot.LastScreen) > 0 {
|
||||
_, _ = clientConn.Write(slot.LastScreen)
|
||||
}
|
||||
@@ -781,6 +784,21 @@ func upstreamReader(s *UserMasterSession, slot *SessionSlot, slotIdx int) {
|
||||
// Cap buffer at 64KB to avoid unbounded memory use from constant ticks
|
||||
if len(recBuf) > 65536 {
|
||||
recBuf = recBuf[len(recBuf)-16384:]
|
||||
if !isActive {
|
||||
slot.Mu.Lock()
|
||||
slot.DiscardCount++
|
||||
discardLimit := slot.AutoHoldDiscardLimit
|
||||
if discardLimit == 0 {
|
||||
discardLimit = defaultAutoHoldDiscardLimit
|
||||
}
|
||||
if discardLimit > 0 && slot.DiscardCount >= discardLimit {
|
||||
slot.IsHeld = true
|
||||
slot.ScreenChanged = false
|
||||
slot.DiscardCount = 0
|
||||
log.Printf("[%s] '%s' System [%d] %s placed on automatic HOLD (raw receive buffer discard loop detected)", displayTag, username, slotIdx+1, slot.System.Name)
|
||||
}
|
||||
slot.Mu.Unlock()
|
||||
}
|
||||
}
|
||||
recBuf = append(recBuf, data...)
|
||||
for {
|
||||
@@ -870,8 +888,41 @@ func upstreamReader(s *UserMasterSession, slot *SessionSlot, slotIdx int) {
|
||||
continue
|
||||
}
|
||||
|
||||
now := time.Now()
|
||||
|
||||
// Auto-hold loop detection for background sessions:
|
||||
// 1. High frequency write updates (excessive update rate loop)
|
||||
if !isActive {
|
||||
burstLimit := slot.AutoHoldBurstLimit
|
||||
if burstLimit == 0 {
|
||||
burstLimit = defaultAutoHoldBurstLimit
|
||||
}
|
||||
if burstLimit > 0 {
|
||||
if slot.WriteBurstWindow.IsZero() || now.Sub(slot.WriteBurstWindow) > autoHoldBurstWindow {
|
||||
slot.WriteBurstCount = 1
|
||||
slot.WriteBurstWindow = now
|
||||
} else {
|
||||
slot.WriteBurstCount++
|
||||
}
|
||||
|
||||
if slot.WriteBurstCount >= burstLimit {
|
||||
slot.IsHeld = true
|
||||
slot.ScreenChanged = false
|
||||
slot.WriteBurstCount = 0
|
||||
slot.DiscardCount = 0
|
||||
log.Printf("[%s] '%s' System [%d] %s placed on automatic HOLD (excessive update rate detected)", displayTag, username, slotIdx+1, slot.System.Name)
|
||||
if isEraseWrite || len(slot.LastScreen) == 0 {
|
||||
slot.LastScreen = bytes.Clone(screenData)
|
||||
}
|
||||
slot.Mu.Unlock()
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if isEraseWrite || len(slot.LastScreen) == 0 {
|
||||
slot.LastScreen = bytes.Clone(screenData)
|
||||
slot.DiscardCount = 0
|
||||
} else if len(slot.LastScreen)+len(screenData) <= maxBuf {
|
||||
slot.LastScreen = append(slot.LastScreen, screenData...)
|
||||
} else {
|
||||
@@ -886,6 +937,33 @@ func upstreamReader(s *UserMasterSession, slot *SessionSlot, slotIdx int) {
|
||||
newBuf = append(newBuf, slot.LastScreen[:baseLen]...)
|
||||
newBuf = append(newBuf, screenData...)
|
||||
slot.LastScreen = newBuf
|
||||
|
||||
// Auto-hold loop detection for background sessions:
|
||||
// 2. Buffer overflow discard loop (repeated discards of older intermediate writes)
|
||||
if !isActive {
|
||||
discardLimit := slot.AutoHoldDiscardLimit
|
||||
if discardLimit == 0 {
|
||||
discardLimit = defaultAutoHoldDiscardLimit
|
||||
}
|
||||
if discardLimit > 0 {
|
||||
if slot.DiscardWindow.IsZero() || now.Sub(slot.DiscardWindow) > autoHoldDiscardWindow {
|
||||
slot.DiscardCount = 1
|
||||
slot.DiscardWindow = now
|
||||
} else {
|
||||
slot.DiscardCount++
|
||||
}
|
||||
|
||||
if slot.DiscardCount >= discardLimit {
|
||||
slot.IsHeld = true
|
||||
slot.ScreenChanged = false
|
||||
slot.DiscardCount = 0
|
||||
slot.WriteBurstCount = 0
|
||||
log.Printf("[%s] '%s' System [%d] %s placed on automatic HOLD (discard loop detected)", displayTag, username, slotIdx+1, slot.System.Name)
|
||||
slot.Mu.Unlock()
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if !isActive {
|
||||
slot.ScreenChanged = true
|
||||
|
||||
Reference in New Issue
Block a user