You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@thrift.apache.org by "Dmytro Shteflyuk (Jira)" <ji...@apache.org> on 2026/08/23 23:22:00 UTC

[jira] [Resolved] (THRIFT-6153) Reduce native Ruby Compact Protocol varint write overhead

     [ https://issues.apache.org/jira/browse/THRIFT-6153?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel ]

Dmytro Shteflyuk resolved THRIFT-6153.
--------------------------------------
    Resolution: Fixed

> Reduce native Ruby Compact Protocol varint write overhead
> ---------------------------------------------------------
>
>                 Key: THRIFT-6153
>                 URL: https://issues.apache.org/jira/browse/THRIFT-6153
>             Project: Thrift
>          Issue Type: Bug
>          Components: Ruby - Library
>            Reporter: Dmytro Shteflyuk
>            Assignee: Dmytro Shteflyuk
>            Priority: Major
>          Time Spent: 40m
>  Remaining Estimate: 0h
>
> h3. Problem
> The native Ruby Compact Protocol encoder writes each byte of a multibyte varint through the transport separately. Encoding boundary i32 and i64 values therefore creates five or ten one-byte Ruby strings and performs five or ten dynamic transport calls instead of one buffered call.
> h3. Client impact
> Ruby clients that serialize integer-heavy Compact payloads pay avoidable object-allocation and method-dispatch costs. The overhead is most visible for small payloads, where protocol framing and scalar writes dominate. The encoded wire bytes remain correct.
> h3. Reproduction
> Run the following from an Apache Thrift checkout after building the Ruby native extension:
> {code:ruby}
> require "thrift"
> class RecordingTransport < Thrift::BaseTransport
>   attr_reader :writes
>   def initialize
>     @writes = []
>   end
>   def write(data)
>     @writes << data.dup
>   end
> end
> def encode(type, value)
>   transport = RecordingTransport.new
>   protocol = Thrift::CompactProtocol.new(transport)
>   protocol.public_send(type, value)
>   name = type.to_s.delete_prefix("write_")
>   bytes = transport.writes.join.unpack1("H*")
>   puts "#{name} writes=#{transport.writes.length} bytes=#{bytes}"
> end
> puts "native=#{Thrift::CompactProtocol.new(RecordingTransport.new).native?}"
> encode(:write_i32, -(2**31))
> encode(:write_i64, -(2**63))
> {code}
> Testing on master commit {{c8f876181c4fa132b5a6b42fdbfe04db06b4eee9}} produces:
> {noformat}
> native=true
> i32 writes=5 bytes=ffffffff0f
> i64 writes=10 bytes=ffffffffffffffffff01
> {noformat}
> h3. Expected behavior
> The native Compact Protocol encoder should accumulate each varint in a bounded stack buffer and call the transport's write method once. This should preserve the exact wire bytes and generic transport behavior while reducing per-scalar overhead.



--
This message was sent by Atlassian Jira
(v8.20.10#820010)