fix: close stream adaptive gaps and switch notify to stario v0.1.1

- make stream fast path honor adaptive soft payload limits end-to-end
  - split oversized fast-stream payloads into sequential frames before batching
  - use adaptive soft cap when encoding stream batch payloads
  - move timeout-like error detection into production code for adaptive tx
  - tune notify FrameReader read size explicitly to avoid throughput regression
  - drop local stario replace and depend on released b612.me/stario v0.1.1
This commit is contained in:
2026-04-18 16:05:57 +08:00
parent 4f760f2807
commit f038a89771
76 changed files with 12656 additions and 906 deletions
+37 -13
View File
@@ -3,7 +3,6 @@ package notify
import (
"context"
"fmt"
"strconv"
"strings"
"sync"
"sync/atomic"
@@ -17,7 +16,7 @@ type streamRuntime struct {
mu sync.RWMutex
handler func(StreamAcceptInfo) error
streams map[string]*streamHandle
data map[string]*streamHandle
data map[string]map[uint64]*streamHandle
cfg streamConfig
flow *streamFlowController
}
@@ -27,7 +26,7 @@ func newStreamRuntime(rolePrefix string) *streamRuntime {
return &streamRuntime{
rolePrefix: rolePrefix,
streams: make(map[string]*streamHandle),
data: make(map[string]*streamHandle),
data: make(map[string]map[uint64]*streamHandle),
cfg: cfg,
flow: newStreamFlowController(cfg),
}
@@ -72,18 +71,23 @@ func (r *streamRuntime) register(scope string, stream *streamHandle) error {
if stream == nil || stream.id == "" {
return errStreamIDEmpty
}
scope = normalizeFileScope(scope)
key := streamRuntimeKey(scope, stream.id)
dataKey := streamRuntimeDataKey(scope, stream.dataID)
r.mu.Lock()
defer r.mu.Unlock()
if _, ok := r.streams[key]; ok {
return errStreamAlreadyExists
}
if stream.dataID != 0 {
if _, ok := r.data[dataKey]; ok {
dataScope := r.data[scope]
if dataScope == nil {
dataScope = make(map[uint64]*streamHandle)
r.data[scope] = dataScope
}
if _, ok := dataScope[stream.dataID]; ok {
return errStreamAlreadyExists
}
r.data[dataKey] = stream
dataScope[stream.dataID] = stream
}
r.streams[key] = stream
return nil
@@ -104,10 +108,14 @@ func (r *streamRuntime) lookupByDataID(scope string, dataID uint64) (*streamHand
if r == nil || dataID == 0 {
return nil, false
}
key := streamRuntimeDataKey(scope, dataID)
scope = normalizeFileScope(scope)
r.mu.RLock()
defer r.mu.RUnlock()
stream, ok := r.data[key]
dataScope := r.data[scope]
if dataScope == nil {
return nil, false
}
stream, ok := dataScope[dataID]
return stream, ok
}
@@ -115,11 +123,17 @@ func (r *streamRuntime) remove(scope string, streamID string) {
if r == nil || streamID == "" {
return
}
scope = normalizeFileScope(scope)
key := streamRuntimeKey(scope, streamID)
r.mu.Lock()
defer r.mu.Unlock()
if stream := r.streams[key]; stream != nil && stream.dataID != 0 {
delete(r.data, streamRuntimeDataKey(scope, stream.dataID))
if dataScope := r.data[scope]; dataScope != nil {
delete(dataScope, stream.dataID)
if len(dataScope) == 0 {
delete(r.data, scope)
}
}
}
delete(r.streams, key)
}
@@ -131,6 +145,20 @@ func (r *streamRuntime) acquireOutbound(ctx context.Context, size int) (func(),
return r.flow.acquire(ctx, size)
}
func (r *streamRuntime) tryAcquireOutbound(size int) bool {
if r == nil || r.flow == nil {
return true
}
return r.flow.tryAcquire(size)
}
func (r *streamRuntime) releaseOutbound(size int) {
if r == nil || r.flow == nil {
return
}
r.flow.release(size)
}
func (r *streamRuntime) snapshots() []StreamSnapshot {
if r == nil {
return nil
@@ -182,10 +210,6 @@ func streamRuntimeKey(scope string, streamID string) string {
return normalizeFileScope(scope) + "\x00" + streamID
}
func streamRuntimeDataKey(scope string, dataID uint64) string {
return normalizeFileScope(scope) + "\x01" + strconv.FormatUint(dataID, 10)
}
func (c *ClientCommon) getStreamRuntime() *streamRuntime {
if c == nil {
return nil