Repository navigation
feat: add raw_data mode to skip value serialization (re-implement #131) #313
Description
Problem
Some applications already use the 32-bit memcached flags field for their own data. When bmemcached reads one of these keys, it interprets the flags bits as its own type flags (object, integer, long, compressed, binary). The client then tries to decompress, unpickle, or int() the value, and the read fails.
PR #131 by @rkday proposed a raw_data mode for this case. That PR targets 2018 code and does not apply to the current main. This issue describes a re-implementation on main that keeps the public API compatible.
Scope (option A)
Add an opt-in raw_data=False keyword argument. If raw_data is True:
- Reads return the stored
bytesvalue. The client ignores the flags field. - Writes send the value without serialization and with
flags=0. - The client does not compress values.
The default raw_data=False keeps the current behavior. The flags bits and the stored data format do not change.
Out of scope: a per-call flags= argument on set/add/replace. In raw mode, a write overwrites the flags that another application set on the key. The docs must state this.
Implementation
- Add
raw_data=Falseas the last parameter in these signatures:Protocol.__init__inbmemcached/protocol.pyClientMixin.__init__inbmemcached/client/mixin.pyDistributedClient.__init__inbmemcached/client/distributed.py
- Keep
raw_dataaftertls_context.DistributedClientpasses arguments tosuper().__init__by position, and users can also call the clients by position. - In
DistributedClient.__init__, passraw_datatosuper().__init__. - In
ClientMixin, storeself.raw_data. Pass it to eachProtocolinset_servers. - In
Protocol.serialize, add a raw-mode branch before the type checks:- If
compress_level > 0, raiseMemcachedException. Compression is not possible in raw mode. - If the value is not
bytes, raiseTypeError. Do not encodestrorintvalues. - Return
(0, value).
- If
- In
Protocol.deserialize, ifself.raw_dataisTrue, returnvaluebefore the flags checks. - Add docstrings for
raw_datainClientMixin(andProtocolif it has parameter docs). State that the defaultcompress_level=-1means "no compression" in raw mode. - Update the docs in
docs/with a short usage section.
Tests
Add tests in test/:
- Raw round-trip:
setandgetof abytesvalue withClient(raw_data=True). - Flags collision: write a value with flags
0x8(compressed) or0x1(object) through a normal client or a raw socket. Read it withraw_data=True. The result must be the original bytes. setof astrorintvalue in raw mode raisesTypeError.setwithcompress_level=9in raw mode raisesMemcachedException.- A large value (more than
COMPRESSION_THRESHOLD) in raw mode is stored without compression. get_multiandset_multiin raw mode.DistributedClient(raw_data=True)round-trip.- Default clients keep the current behavior. The existing suite covers this.
Verification
Run these commands:
pytest -sruff check .ruff format --check .
Pull request
- Title:
feat: add raw_data mode to skip value serialization - Credit @rkday and link Add support for raw data flag #131.
- Close Add support for raw data flag #131 after the new pull request merges.
Activity