Repository navigation
perf(redis): reduce large String receive and segment copies - #339
Conversation
|
Warning Review limit reachedYou've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository. Next included review available in 20 minutes. View limit details
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info
WalkthroughThe RESP parser and server now support bounded direct reads into large bulk arguments. The change adds client-buffer reservation and query-limit checks, plus unit and TCP/TLS end-to-end tests. It also updates the bycorf reference and changes StringPage entry construction. ChangesLarge RESP bulk receive
StringPage initialization
Priority: ⬇️ Low Estimated code review effort: 3 (Moderate) | ~25 minutes Change: Feature Sequence Diagram(s)sequenceDiagram
participant ReadCommandBatch
participant RespCommandParser
participant ClientBufferReservation
participant BycorfRead
ReadCommandBatch->>RespCommandParser: Get bulk reservation size
ReadCommandBatch->>ClientBufferReservation: Reserve destination bytes
ReadCommandBatch->>RespCommandParser: Prepare argument storage
ReadCommandBatch->>RespCommandParser: Get writable bulk buffer
ReadCommandBatch->>BycorfRead: Read bytes into writable buffer
BycorfRead-->>ReadCommandBatch: Return received bytes
ReadCommandBatch->>RespCommandParser: Commit bytes after query-limit refresh
Suggested reviewers: Merge Risk: ⚪ Minimal · up to
|
Context
A 1 MiB SET currently passes through roughly 256 small receive/parse rounds and copies each body fragment into a growing argument string. Grouped String page construction also copies the segment through a const initializer-list element.
Uses the buffered-read API merged in eloqdata/bycorf#15. The Bycorf submodule is pinned to current upstream main
0f7b4c0730d515422531528ecacb65457afdd939, the same revision as Lavik main.Behavior before and after
Small requests keep their existing receive path. Once a bulk argument of at least 32 KiB has started arriving, the server can prepay a bounded destination and receive directly into the final argument string. The runtime's opt-in read drains already queued buffers without waiting to fill the destination. TCP and TLS preserve command framing and pipeline order; TLS retains its existing decrypted-read behavior.
Grouped String pages now move the owned segment into a vector entry. A full 1 MiB SET avoids 128 additional segment-string allocations/copies; partial String updates also avoid the corresponding changed-segment copy.
Implementation
Design decisions and alternatives
Increasing only the application buffer would still leave the runtime returning one 4 KiB receive buffer per call. The opt-in runtime API avoids enlarging every worker's receive pool or changing existing ReadSome callers. String resize initializes writable storage safely; this removes intermediate copies and growth but does not eliminate every memory write. Client accounting remains a request-byte quota, not exact allocator-capacity accounting.
Documentation and comments
Updated the request-serving architecture, client-buffer API comments, and metrics documentation/help to describe prepaid direct-read destinations and their lifetime. The grouped storage format and publication model are unchanged.
Test plan
Initial validation used GCC 13 Debug on ARM64, before merging current Lavik main:
All 83 selected unit tests, both network suites, and all 7 selected String write/crash-recovery cases passed, without skips. Network coverage includes TCP/TLS binary roundtrips across multiple reservation windows, mixed small/large pipelines, MSET, MULTI/EXEC/DISCARD, partial EOF, malformed framing, live query-limit shrink, and quota rejection/release. The runtime dependency's five checks also passed.
After merging Lavik main
1af140496, the only conflict was the Bycorf submodule reference. It now points to upstream main0f7b4c0730d515422531528ecacb65457afdd939, whose tree is identical to previously tested runtime headc4ec8208a15279e9484a07f74bdec51cfe8e6b5f. The non-submodule patch against the new base has the same stable patch ID as the original PR. Combined String ownership/locking review, format/lint checks, Python syntax compilation and diff checks passed. Local functional tests were not rerun for this merge-only update; CI is rerunning on the final merged commit.This host falls back from provided-buffer-ring setup to one-shot receive. Batched queue behavior is covered by deterministic runtime queue tests; production multishot throughput and the original 80-connection workload have not been benchmarked here.
Risk assessment
The main risk is confusing prepaid bytes with received bytes or publishing an unwritten tail. Separate parser state and integration checks cover these boundaries. A slow sender that starts a large body may hold a bounded prepaid window; it counts against the existing client quota and is released on disconnect. Small-request throughput has not been claimed from the functional checks.
Rollback plan
Revert this PR, including the runtime pin. No data migration is required.
Reviewer guide
Review parser state and server charge transfer together, then the network ownership tests. The first commit contains only the StringPage copy fix for isolated comparison. The merged main includes the worker store-lock preparation change from #340 and record CRC controls from #341. Both are baseline changes; this PR retains only the receive and StringPage copy optimizations.
Follow-up work
Rerun the original large-value benchmark to measure throughput and tail latency; no end-to-end speedup is asserted from source inspection.