Repository navigation
v5.2.0
Adds Dalli::CacheResult (#1156) and the opt-in defer_drain option (#1168), several get_multi/set/delete performance improvements from radixdev, and a fix for multi-server get_multi with empty values (#1170), which could silently return another key's value. Upgrading is recommended.
Features:
- Add
Dalli::CacheResult, returned by the new#get_with_metadata_resultand#get_multi_with_metadata_result(#1156)- An opt-in, typed view over the Hash that
#get_with_metadataand#get_multi_with_metadataalready return; those methods are unchanged, and changing their return type is left for a future major version (#1151) value,cas,hit_before,last_accessandttl_remainingreaders (the last three arenilunless requested), plusmiss?,hit?,stale?,won_recache?andlost_recache?predicates- Results are frozen, and a Hash that claims to be both a miss and stale raises
ArgumentError #get_multi_with_metadata_resultomits misses and acceptsreq_options:, like#get_multi_with_metadata; it has no block form
- An opt-in, typed view over the Hash that
- Add the opt-in
defer_drainclient option (#1168)- With
defer_drain: true, aquiet/multiblock no longer waits at its end for the replies to its requests. The requests are still sent right away; the replies are read with one noop per server just before the next non-quiet request to that server - Adds
Client#drain_deferred_responses, to drain at a boundary of the caller's choosing (the end of a web request or job) - Tradeoff: an error reply to a quiet request surfaces (and is discarded) at that later point, not at the end of the block
- Off by default, so existing behavior is unchanged
- Replies memcached sends for quiet requests wait on the connection until they're drained, so a client that only makes quiet requests should call
drain_deferred_responsesperiodically; see "Deferred Draining" in the README - Thanks to Julian Richard Contreras and Matt Dick for this contribution
- With
Performance:
- Skip the empty read at the end of each pipelined
read_availablecall (#1164)- A read shorter than the chunk size means the socket is drained, so the extra
read_nonblockthat only returned:wait_readableis gone; theIO.selectloop still picks up anything that arrives later - Saves one syscall per server per multi-server
get_multi; on 4 servers a 3-keyget_multigoes from 16% to 5% slower than 2.7.11 in the #930 benchmark - TLS sockets also check
SSLSocket#pending, sinceIO.selectcannot see data OpenSSL has buffered - Thanks to Julian Richard Contreras for this contribution
- A read shorter than the chunk size means the socket is drained, so the extra
- Reduce Ruby overhead on plain
setanddelete(#1166)- A
setwith no CAS, routing tokens or quiet mode builds itsmsrequest with one string interpolation (RequestFormatter.plain_meta_set), and adeletewith no options usesplain_meta_delete; both produce the same bytes as before HD c<cas>,HDandNFreplies are parsed without splitting them into tokens- Allocations per
setdrop from 22 to 18, and perdeletefrom 12 to 7 - Thanks to Julian Richard Contreras for this contribution
- A
- Only drain servers that were sent quiet requests when a
quiet/multiblock ends (#1167)- Ending the block used to send a noop to every server in the ring and wait for each reply, one after another, so its cost grew with ring size even when the block touched one server (or none)
- Each connection now records when a quiet request is written, and the block's drain skips the others; servers that were never connected are no longer connected just to be drained
- With ~300us of network round trip,
multi { set }on a 16-server ring goes from 4.9ms to 0.32ms; an empty block no longer touches the network - Thanks to Julian Richard Contreras for this contribution
- Reduce Ruby overhead in
get_multireply parsing and key routing (#1169)VAreply headers are read in place instead of being split into tokens, on both the multi-server (pipelined) and single-server paths; results are unchanged, and unusual headers still take the token path- A key's server is found through a bucket table over the ring's continuum instead of a binary search, and the key's own server is tried before the failover loop; the server chosen for every key is unchanged
- Allocations for a 100-key
get_multion 4 servers drop from 1,500 to 1,104; over loopback it goes from 301us to 243us - Thanks to Julian Richard Contreras for this contribution
Bug fixes:
- Fix multi-server
get_multistopping at an empty value (#1170)- The pipelined reply parser took a hit on a zero-length value (
VA 0) for the terminatingMN, so that server's remaining keys were silently missing from the result - Its value terminator and any replies not yet parsed stayed on the connection and were read as the replies to later commands on it. Those commands could fail with
Dalli::DalliError: Response error, or a single-keygetcould silently return another key's value - An empty value is now returned as
'', like a single-keygetand single-serverget_multi - Affects the meta protocol since 3.2.0 (the default since 5.0.0)
- Thanks to Julian Richard Contreras for this contribution
- The pipelined reply parser took a hit on a zero-length value (