Skip to content

Enable RuboCop Style/UnpackFirst - #3722

Merged
kpumuk merged 1 commit into
apache:masterfrom
kpumuk:rb-rubocop-unpack-first
Aug 16, 2026
Merged

Enable RuboCop Style/UnpackFirst#3722
kpumuk merged 1 commit into
apache:masterfrom
kpumuk:rb-rubocop-unpack-first

Conversation

@kpumuk

@kpumuk kpumuk commented Aug 16, 2026

Copy link
Copy Markdown
Member

Enable Style/UnpackFirst and replace single-value unpack(...).first and parallel-assignment unpacking with unpack1 throughout the Ruby library and tests. Binary protocol i16 and i32 reads now avoid an intermediate array alongside double reads and UUID byte decoding.

Benchmarks

The repository protocol benchmark compared upstream/master with this branch using Ruby 4.0.6 on aarch64 Linux. Each result is the median of seven isolated invocations; every invocation includes the harness warm-up pass.

THRIFT_BENCHMARK_SKIP_NATIVE=1 ruby test/rb/benchmarks/protocol_benchmark.rb \
  --json \
  --large-runs 3 \
  --small-runs 20000 \
  --scenarios rb-bin-read-large,rb-cmp-read-large,rb-bin-read-small,rb-cmp-read-small,hdr-bin-read-small,hdr-cmp-read-small,hdr-zlib-read-small
Read scenario upstream/master This branch Change
Ruby binary, three large structures 1.3304 s 1.2904 s -3.0%
Ruby compact, three large structures 1.2256 s 1.2251 s -0.04%
Ruby binary, 20,000 small structures 0.3874 s 0.3704 s -4.4%
Ruby compact, 20,000 small structures 0.3578 s 0.3531 s -1.3%
Header binary, 20,000 small structures 0.6312 s 0.5973 s -5.4%
Header compact, 20,000 small structures 0.6115 s 0.5965 s -2.4%
Header zlib, 20,000 small structures 0.7031 s 0.6749 s -4.0%

A separate stdlib-only primitive benchmark measured 500,000 operations in isolated processes with GC disabled. Each replacement removed one allocation per operation and reduced retained memory:

Operation Allocations/op Retained RSS
double (G) 2 → 1 38.7 → 19.1 MiB
UUID hex (H*) 3 → 2 77.6 → 57.9 MiB
i16 (n) 2 → 1 38.7 → 19.1 MiB
i32 (N) 2 → 1 38.8 → 19.1 MiB

The protocol benchmark measures only the selected pure-Ruby read scenarios, while the primitive benchmark isolates unpacking allocation cost; neither predicts complete application throughput.

  • Did you create an Apache Jira ticket? (Request account here, not required for trivial changes)
  • If a ticket exists: Does your pull request title follow the pattern "THRIFT-NNNN: describe my issue"?
  • Did you squash your changes to a single commit? (not required, but preferred)
  • Did you do your best to avoid breaking changes? If one was needed, did you label the Jira ticket with "Breaking-Change"?
  • If your change does not involve any code, include [skip ci] anywhere in the commit message to free up build resources.

Client: rb

Co-Authored-By: OpenAI Codex (GPT-5.6) <codex@openai.com>
Copilot AI lite review requested due to automatic review settings August 16, 2026 18:20
@mergeable mergeable Bot added the ruby Pull requests that update Ruby code label Aug 16, 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.

Pull request overview

Enables RuboCop Style/UnpackFirst for the Ruby codebase and updates Ruby library + specs to use String#unpack1 in places that previously used unpack(...).first (or single-value parallel assignment), reducing intermediate array allocations in hot paths.

Changes:

  • Enable Style/UnpackFirst in lib/rb/.rubocop.yml.
  • Replace unpack(...).first / single-value unpacking with unpack1 across Ruby library and specs.
  • Reduce allocations in protocol reads (notably binary i16/i32/double) and UUID hex decoding by avoiding intermediate arrays.

Reviewed changes

Copilot reviewed 10 out of 10 changed files in this pull request and generated no comments.

Show a summary per file
File Description
lib/rb/.rubocop.yml Enables Style/UnpackFirst to enforce unpack1 usage.
lib/rb/lib/thrift/protocol/binary_protocol.rb Uses unpack1 for i16/i32/double reads to avoid intermediate arrays.
lib/rb/lib/thrift/protocol/compact_protocol.rb Uses unpack1 for protocol id and double reads.
lib/rb/lib/thrift/server/nonblocking_server.rb Uses unpack1 when decoding framed message sizes.
lib/rb/lib/thrift/struct_union.rb Uses unpack1 for binary-to-hex inspection formatting.
lib/rb/lib/thrift/transport/framed_transport.rb Uses unpack1 when reading frame size.
lib/rb/lib/thrift/transport/header_transport.rb Uses unpack1 for frame size, magic, flags, and header parsing.
lib/rb/lib/thrift/uuid.rb Uses unpack1 for UUID hex decoding from bytes.
lib/rb/spec/header_protocol_spec.rb Updates spec assertions to use unpack1.
lib/rb/spec/header_transport_spec.rb Updates spec assertions to use unpack1.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

@kpumuk
kpumuk merged commit 76ae984 into apache:master Aug 16, 2026
94 of 95 checks passed
@kpumuk
kpumuk deleted the rb-rubocop-unpack-first branch August 16, 2026 18:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ruby Pull requests that update Ruby code

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants