Fix multi-server get_multi stopping at an empty value - #1170
Merged
petergoldstein merged 4 commits intoOct 2, 2026
Merged
Conversation
getk_response_from_buffer returned the no-body result for any header with a zero size, which the pipelined getter reads as the terminating MN. A VA 0 hit therefore ended the server's pipeline early, dropping its remaining keys and leaving the rest of its replies unread on the connection. Parse a VA 0 as an empty value instead. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
radixdev
marked this pull request as ready for review
September 29, 2026 16:02
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Owner
|
Thanks, merged. While testing I found the impact goes beyond missing keys: on This is shipping in 5.2.0, plus backports in 5.1.2, 5.0.8, 4.3.5 and 3.2.11 (the meta protocol has had this since 3.2.0). CI was also failing on every PR because the runner images' package index went stale for libevent. That's fixed in #1172. |
This was referenced Oct 2, 2026
Merged
Merged
Merged
Merged
Merged
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
On a multi-server ring, a
get_multithat includes a key whose value is empty stops reading that key's server at that key. The rest of that server's keys are silently missing from the result. The unread replies stay on the connection, and with larger values they corrupt the next command on it.This PR parses a zero-length hit (
VA 0) as an empty value instead. It's a one-line change inlib/.Cause
ResponseProcessor#getk_response_from_buffertreats any header whose size is zero as a reply with no body:That covers the terminating
MNand error lines, but it also catchesVA 0 ... s0.Base#pipeline_next_responsesthen sees an OK status with no key, which is how it recognizes theMN, and callsfinish_pipeline. TheVA 0reply's own terminator and the replies after it are never parsed:Reproduction
On
main, with 2 memcached servers, 200 keys, andkey5set to''viaset('key5', '', 0, raw: true):get_multireturnedraw: truegets correctraw: truegetraisesDalli::DalliError: Response error: 8k18k18k1…(value bytes read as a reply)gets correctserializer: JSONgets correctWith this PR, every row returns 200 of 200, with
key5as'', and every latergetreturns the right value.A Marshal or JSON client never writes an empty value itself. It still reads one, though, if another client, another language, or a
raw: truewrite stored one. A single-keygetand a single-serverget_multialready return''for these.The logic dates from the meta protocol's pipelined getter in 3.2.0. It was opt-in until 5.0.0, where it became the only protocol.
Change
getk_response_from_bufferkeeps the no-body result for headers other thanVA. AVA 0now goes through the normal path: the response size includes the empty body's terminator, it returns[0]until that terminator has arrived, and the value is''afterretrieve.Testing
bundle exec rake: 848 runs, 0 failures, 0 errors.mainand pass with this change.ResponseProcessor: aVA 0hit returns the key,''and a size that includes the terminator.ResponseProcessor: aVA 0whose terminator hasn't arrived yet returns[0].raw: true: 100 keys of 20KB with one empty value. The hash and block forms ofget_multireturn every key, and agetof every key afterwards returns the right value.bundle exec rubocop: no offenses.This is independent of #1169, which leaves zero sizes on the existing token path. Whichever lands second needs a trivial rebase.
This PR was generated with the assistance of Claude Code (Anthropic). The reproduction and test results above come from real runs.
🤖 Generated with Claude Code