Skip to content

THRIFT-6436: Avoid repeated bytes concatenation in Python readAll - #4028

Open
OneSizeFitsQuorum wants to merge 1 commit into
apache:masterfrom
OneSizeFitsQuorum:THRIFT-6436
Open

OneSizeFitsQuorum wants to merge 1 commit into
apache:masterfrom
OneSizeFitsQuorum:THRIFT-6436

Conversation

@OneSizeFitsQuorum

@OneSizeFitsQuorum OneSizeFitsQuorum commented Oct 20, 2026 •

Copy link
Copy Markdown

JIRA: https://issues.apache.org/jira/browse/THRIFT-6436
Client: py

TTransportBase.readAll repeatedly copies the accumulated bytes when a read completes through multiple short reads. Collect chunks and join them once instead. A short inline comment explains why chunks are joined once.

The patch is limited to the accumulation loop and seven regression tests in the existing transport test file. They cover fragmented and single reads, remaining request sizes, nonpositive sizes, EOF, exception propagation, consecutive reads, and a fragmented frame.

Local performance validation

A separate Python TSimpleServer process returned a prebuilt 30 MiB binary payload over loopback TCP, using TBinaryProtocol and TFramedTransport. Only the client's readAll implementation differed. Each implementation had seven alternating rounds of three measured RPCs, with one warm-up per round. Values below are medians over 21 RPCs; timing excludes connection setup and payload verification. Frame/string limits were explicitly configured for the large test response.

Environment: CPython 3.10.12, Linux 6.8.0-136-generic x86_64, Intel Xeon Platinum 8362 @ 2.80 GHz, eight logical CPUs visible. Baseline: db8caa7.

Socket read mode RPC wall time, before → after Client CPU time, before → after Payload throughput, before → after
Unrestricted 76.44 → 50.96 ms 39.56 → 14.88 ms 392.5 → 588.7 MiB/s
Requests capped at 64 KiB 732.53 → 49.96 ms 695.42 → 15.30 ms 41.0 → 600.5 MiB/s

Unrestricted frame-body read counts ranged from 11–14 before and 136–437 after, so fragmentation was not identical. The explicitly controlled 64 KiB case used exactly 481 body reads for both implementations. These are local synthetic-service measurements, not HBase throughput results or predictions for other deployments. The RPC harness and raw results remain local.

Standalone reproduction of fragmented-read cost

This is an in-memory check of the accumulation cost, independent of the TCP measurements above. After checking out this PR:

(cd lib/py && python3 setup.py build)
git show HEAD^:lib/py/src/transport/TTransport.py > /tmp/readall-before.py
PYTHONPATH=lib/py/test python3 - <<'PY'
import importlib.util
import statistics
import timeit

import _import_local_thrift
from thrift.transport.TTransport import TTransportBase

spec = importlib.util.spec_from_file_location('baseline', '/tmp/readall-before.py')
baseline = importlib.util.module_from_spec(spec)
spec.loader.exec_module(baseline)
data = bytes(range(256)) * (30 * 1024 * 1024 // 256)
width = (len(data) + 54) // 55
chunks = [data[i:i + width] for i in range(0, len(data), width)]


class Fragmented(TTransportBase):
    def __init__(self):
        self.chunks = iter(chunks)

    def read(self, size):
        return next(self.chunks, b'')


for label, implementation in (
    ('before', baseline.TTransportBase.readAll), ('after', TTransportBase.readAll)
):
    assert implementation(Fragmented(), len(data)) == data
    times = timeit.repeat(lambda: implementation(Fragmented(), len(data)), number=1, repeat=7)
    print(label, round(statistics.median(times) * 1000, 2), 'ms')
PY

Validation

  • The seven new regression tests were added and run against the original implementation before applying the runtime change.

  • All 14 transport tests passed after the change, along with the local TCP A/B measurements above.

  • All 26 Python-specific CI checks passed for the final commit, covering Python 3.10–3.14 on Linux and the macOS matrix, plus Python static analysis.

  • flake8 --max-line-length=100, codespell and git diff --check passed for the final patch.

  • make style is unavailable in this unconfigured checkout because there is no root Makefile.

  • CI environment note: the Smalltalk setup job fails while downloading the Pharo image (curl exit 7), before its tests run. Repository administrator permissions are required to rerun that job.

Generated-by: OpenAI Codex (GPT-6)

Copilot AI balanced review requested due to automatic review settings October 20, 2026 13:06
@mergeable mergeable Bot added the python label Oct 20, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Warning

Copilot couldn't run its full agentic review because it didn't start before the timeout. Make sure your repository has a runner available, or add a copilot-code-review.yml file specifying one with the runs-on attribute. See the docs for more details.

Copilot review overview

3 open issues
What changed in this PR

Improves Python client transport performance by making TTransportBase.readAll accumulate chunks and join() once, avoiding repeated bytes concatenation for fragmented reads.

Changes:

  • Refactor TTransportBase.readAll to collect read chunks in a list and b''.join() at the end.
  • Add regression tests for readAll behavior across fragmentation, EOF, exceptions, and framed payloads.
  • Add a loopback RPC benchmark to compare baseline vs updated readAll behavior and record socket read fragmentation.
File Description
lib/​py/​src/​transport/​TTransport.py Switch readAll from incremental bytes concatenation to list accumulation + join for better performance on fragmented reads.
lib/​py/​test/​thrift_transport.py Add regression tests and a small fragmented transport helper to verify readAll semantics.
lib/​py/​test/​benchmark_readall.py Add a standalone benchmark to measure before/after readAll behavior over a framed RPC on loopback TCP.

Review effort: Lite

Comment thread lib/py/test/thrift_transport.py
Comment thread lib/py/test/benchmark_readall.py Outdated
Comment thread lib/py/test/benchmark_readall.py Outdated
Copilot AI balanced review requested due to automatic review settings October 21, 2026 06:17
@mergeable mergeable Bot added the build and general CI cmake, automake and build system changes label Oct 21, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment thread lib/py/Makefile.am Outdated
Comment thread lib/py/Makefile.am Outdated
Comment thread lib/py/test/benchmark_readall.py Outdated
Copilot AI balanced review requested due to automatic review settings October 21, 2026 08:30

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment thread lib/py/src/transport/TTransport.py
Copilot AI balanced review requested due to automatic review settings October 22, 2026 05:36

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment thread lib/py/test/thrift_transport.py
Comment thread lib/py/src/transport/TTransport.py Outdated
Comment thread lib/py/src/transport/TTransport.py Outdated
Copilot AI balanced review requested due to automatic review settings October 22, 2026 06:44

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Warning

Copilot couldn't run its full agentic review because it didn't start before the timeout. Make sure your repository has a runner available, or add a copilot-code-review.yml file specifying one with the runs-on attribute. See the docs for more details.

Copilot review overview

2 open issues
10 resolved since last review

Review effort: Lite

Comment thread lib/py/src/transport/TTransport.py
Comment thread lib/py/test/thrift_transport.py Outdated
Client: py

Collect readAll chunks and join once, preserving short-read and EOF behavior.
Add regression tests for fragmented reads, read sizes, EOF and exception propagation.

Generated-by: OpenAI Codex (GPT-6)
Copilot AI balanced review requested due to automatic review settings October 22, 2026 07:02

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Warning

Copilot couldn't run its full agentic review because it didn't start before the timeout. Make sure your repository has a runner available, or add a copilot-code-review.yml file specifying one with the runs-on attribute. See the docs for more details.

Copilot review overview

No open issues 🎉

2 resolved since last review

Review effort: Lite

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

build and general CI cmake, automake and build system changes python

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants