- bufferRing: add consumeFront() method to eliminate duplicate buffer
consumption code in tryReadV1/tryReadV2, move allocator.Put() outside
critical section to reduce lock hold time
- Session.IsClosed(): replace select-based check with atomic flag for
faster hot path execution, add 'closed' field with atomic operations
- shaperQueue: convert count to atomic int64, Len() and IsEmpty() now
lock-free using atomic.LoadInt64()
- recvLoop: move stream.fin() and stream.update() calls outside lock
scope in cmdFIN/cmdUPD handlers to reduce lock contention
- stream: extract checkWriteClosed() helper to deduplicate close checks
in writeV1/writeV2
All tests pass with race detector enabled.
- Add writeRequestPool to reuse writeRequest objects and their result
channels in session.go, reducing allocations per write operation
- Add shaperHeapPool to reuse shaperHeap objects in shaper.go, avoiding
heap allocations when streams are created/destroyed
- Pre-allocate buffers and heads slices with capacity 8 in newStream()
to reduce slice growth allocations during data transfer
Benchmark results (128KB data transfer):
Before: 36 allocs/op, ~910 MB/s
After: 20 allocs/op, ~950 MB/s
This reduces memory allocations by 44% and improves throughput by ~5%.
cmdUPD is a v2-only command used for flow control window updates.
Previously, recvLoop would accept and process cmdUPD even when
the session was configured for protocol version 1, which violates
the protocol specification.
This change adds a version check before processing cmdUPD. If the
session is not running v2, it now correctly returns ErrInvalidProtocol
and terminates the receive loop.