thrift 0.22.0 → 0.24.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +235 -17
- data/benchmark/benchmark.rb +23 -8
- data/benchmark/client.rb +50 -6
- data/benchmark/server.rb +46 -7
- data/benchmark/thin_server.rb +2 -0
- data/ext/binary_protocol_accelerated.c +154 -42
- data/ext/bytes.c +14 -0
- data/ext/compact_protocol.c +138 -45
- data/ext/constants.h +12 -0
- data/ext/extconf.rb +17 -8
- data/ext/memory_buffer.c +44 -7
- data/ext/protocol.c +29 -0
- data/ext/protocol.h +35 -0
- data/ext/struct.c +48 -17
- data/ext/thrift_native.c +28 -3
- data/lib/thrift/bytes.rb +70 -100
- data/lib/thrift/client.rb +54 -13
- data/lib/thrift/exceptions.rb +6 -5
- data/lib/thrift/multiplexed_processor.rb +20 -10
- data/lib/thrift/processor.rb +7 -6
- data/lib/thrift/protocol/base_protocol.rb +52 -21
- data/lib/thrift/protocol/binary_protocol.rb +65 -20
- data/lib/thrift/protocol/binary_protocol_accelerated.rb +6 -5
- data/lib/thrift/protocol/compact_protocol.rb +76 -41
- data/lib/thrift/protocol/header_protocol.rb +321 -0
- data/lib/thrift/protocol/json_protocol.rb +44 -27
- data/lib/thrift/protocol/multiplexed_protocol.rb +6 -5
- data/lib/thrift/protocol/protocol_decorator.rb +13 -4
- data/lib/thrift/serializer/deserializer.rb +6 -5
- data/lib/thrift/serializer/serializer.rb +5 -5
- data/lib/thrift/server/base_server.rb +5 -4
- data/lib/thrift/server/mongrel_http_server.rb +7 -6
- data/lib/thrift/server/nonblocking_server.rb +35 -9
- data/lib/thrift/server/simple_server.rb +13 -5
- data/lib/thrift/server/thin_http_server.rb +4 -3
- data/lib/thrift/server/thread_pool_server.rb +7 -6
- data/lib/thrift/server/threaded_server.rb +13 -5
- data/lib/thrift/struct.rb +12 -11
- data/lib/thrift/struct_union.rb +14 -9
- data/lib/thrift/thrift_native.rb +3 -2
- data/lib/thrift/transport/base_server_transport.rb +8 -5
- data/lib/thrift/transport/base_transport.rb +18 -14
- data/lib/thrift/transport/buffered_transport.rb +7 -6
- data/lib/thrift/transport/framed_transport.rb +8 -7
- data/lib/thrift/transport/header_transport.rb +562 -0
- data/lib/thrift/transport/http_client_transport.rb +2 -1
- data/lib/thrift/transport/io_stream_transport.rb +4 -3
- data/lib/thrift/transport/memory_buffer_transport.rb +13 -6
- data/lib/thrift/transport/server_socket.rb +14 -8
- data/lib/thrift/transport/socket.rb +126 -60
- data/lib/thrift/transport/ssl_server_socket.rb +4 -3
- data/lib/thrift/transport/ssl_socket.rb +45 -13
- data/lib/thrift/transport/unix_server_socket.rb +9 -5
- data/lib/thrift/transport/unix_socket.rb +7 -6
- data/lib/thrift/types.rb +10 -6
- data/lib/thrift/union.rb +15 -8
- data/lib/thrift/uuid.rb +50 -0
- data/lib/thrift.rb +4 -1
- data/spec/ThriftSpec.thrift +21 -1
- data/spec/base_protocol_spec.rb +21 -2
- data/spec/base_transport_spec.rb +48 -8
- data/spec/binary_protocol_accelerated_spec.rb +1 -0
- data/spec/binary_protocol_spec.rb +1 -2
- data/spec/binary_protocol_spec_shared.rb +206 -155
- data/spec/bytes_spec.rb +71 -114
- data/spec/client_spec.rb +86 -19
- data/spec/compact_protocol_spec.rb +153 -16
- data/spec/constants_demo_spec.rb +102 -0
- data/spec/exception_spec.rb +1 -1
- data/spec/flat_spec.rb +1 -0
- data/spec/header_protocol_spec.rb +476 -0
- data/spec/header_transport_spec.rb +431 -0
- data/spec/http_client_spec.rb +5 -6
- data/spec/json_protocol_spec.rb +69 -47
- data/spec/multiplexed_processor_spec.rb +75 -0
- data/spec/namespaced_spec.rb +1 -1
- data/spec/nonblocking_server_spec.rb +174 -8
- data/spec/processor_spec.rb +1 -1
- data/spec/recursion_depth_spec.rb +223 -0
- data/spec/serializer_spec.rb +1 -1
- data/spec/server_socket_spec.rb +38 -1
- data/spec/server_spec.rb +60 -9
- data/spec/socket_spec.rb +119 -13
- data/spec/socket_spec_shared.rb +73 -9
- data/spec/spec_helper.rb +2 -1
- data/spec/ssl_server_socket_spec.rb +52 -1
- data/spec/ssl_socket_spec.rb +181 -11
- data/spec/struct_nested_containers_spec.rb +2 -2
- data/spec/struct_spec.rb +114 -9
- data/spec/support/header_protocol_helper.rb +55 -0
- data/spec/thin_http_server_spec.rb +4 -18
- data/spec/types_spec.rb +26 -26
- data/spec/union_spec.rb +70 -11
- data/spec/unix_socket_spec.rb +17 -2
- data/spec/uuid_validation_spec.rb +239 -0
- data/test/fuzz/Makefile +779 -0
- data/test/fuzz/Makefile.am +173 -0
- data/test/fuzz/Makefile.in +775 -0
- data/test/fuzz/README.md +149 -0
- data/test/fuzz/fuzz_common.rb +96 -0
- data/{lib/thrift/core_ext.rb → test/fuzz/fuzz_parse_binary_protocol.rb} +4 -4
- data/{lib/thrift/core_ext/fixnum.rb → test/fuzz/fuzz_parse_binary_protocol_accelerated.rb} +7 -13
- data/test/fuzz/fuzz_parse_binary_protocol_accelerated_harness.rb +23 -0
- data/test/fuzz/fuzz_parse_binary_protocol_harness.rb +23 -0
- data/test/fuzz/fuzz_parse_compact_protocol.rb +23 -0
- data/test/fuzz/fuzz_parse_compact_protocol_harness.rb +23 -0
- data/test/fuzz/fuzz_parse_json_protocol.rb +23 -0
- data/test/fuzz/fuzz_parse_json_protocol_harness.rb +23 -0
- data/test/fuzz/fuzz_roundtrip_binary_protocol.rb +23 -0
- data/test/fuzz/fuzz_roundtrip_binary_protocol_accelerated.rb +23 -0
- data/test/fuzz/fuzz_roundtrip_binary_protocol_accelerated_harness.rb +23 -0
- data/test/fuzz/fuzz_roundtrip_binary_protocol_harness.rb +23 -0
- data/test/fuzz/fuzz_roundtrip_compact_protocol.rb +23 -0
- data/test/fuzz/fuzz_roundtrip_compact_protocol_harness.rb +23 -0
- data/test/fuzz/fuzz_roundtrip_json_protocol.rb +23 -0
- data/test/fuzz/fuzz_roundtrip_json_protocol_harness.rb +23 -0
- data/test/fuzz/fuzz_tracer.rb +29 -0
- metadata +105 -70
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 90306a751b8d883922c4556778391d56c8c48fbf008187d3edfe411db4e9f6f7
|
|
4
|
+
data.tar.gz: 95287ba8714521389775a7d2ad265b3ad60a3ca44ada102abcf0c2ee152347cd
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: d7e052575e5b7e581440a9073d2f4c6ce828b79963f7ce5c077f77e7c759b3589d5671a9e6f37ff4df996061af6b77362cc6248c7d22ac414156594b3fd77339
|
|
7
|
+
data.tar.gz: 35f5ee1d30099e5c70fa49d420153442e2b0b97587a908dea86ad1f9a2bbc44df5ff1baa3474cbc48f4064e20571eab7aa00c5fb155202f05edcd17579cbaddf
|
data/README.md
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
Thrift Ruby Software Library
|
|
2
|
-
http://thrift.apache.org
|
|
1
|
+
# Thrift Ruby Software Library
|
|
3
2
|
|
|
4
|
-
|
|
3
|
+
## License
|
|
5
4
|
|
|
6
5
|
Licensed to the Apache Software Foundation (ASF) under one
|
|
7
6
|
or more contributor license agreements. See the NOTICE file
|
|
@@ -20,24 +19,243 @@ KIND, either express or implied. See the License for the
|
|
|
20
19
|
specific language governing permissions and limitations
|
|
21
20
|
under the License.
|
|
22
21
|
|
|
23
|
-
|
|
22
|
+
# Using Thrift with Ruby
|
|
24
23
|
|
|
25
|
-
|
|
26
|
-
|
|
24
|
+
Ruby bindings for the Apache Thrift RPC system. The gem contains the runtime
|
|
25
|
+
types, transports, protocols, and servers used by generated Ruby code for both
|
|
26
|
+
clients and services.
|
|
27
27
|
|
|
28
|
-
|
|
28
|
+
## Compatibility
|
|
29
29
|
|
|
30
|
-
|
|
30
|
+
- Ruby MRI >= 2.7 (tested against current supported releases).
|
|
31
|
+
- JRuby works with the pure-Ruby implementation; the native extension is
|
|
32
|
+
skipped automatically.
|
|
33
|
+
- For the repo-wide transport, protocol, and server support matrix, see
|
|
34
|
+
[Language Feature Matrix](https://github.com/apache/thrift/blob/master/LANGUAGES.md). This README focuses on Ruby-specific
|
|
35
|
+
behavior and migration notes.
|
|
31
36
|
|
|
32
|
-
|
|
37
|
+
## Installation
|
|
33
38
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
thrift
|
|
39
|
+
- Requirements: Ruby >= 2.7.
|
|
40
|
+
- From RubyGems: `gem install thrift`
|
|
41
|
+
- From source: `bundle install`, `gem build thrift.gemspec`, then install the
|
|
42
|
+
resulting `thrift-*.gem`. The native accelerator is built when the gem is
|
|
43
|
+
installed on supported runtimes.
|
|
38
44
|
|
|
39
|
-
|
|
45
|
+
## Generating Ruby Code
|
|
40
46
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
47
|
+
The Ruby library does not include the Thrift compiler. Use a compiler built
|
|
48
|
+
from the root of this repository to generate Ruby bindings:
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
thrift --gen rb path/to/service.thrift
|
|
52
|
+
# with namespaced modules
|
|
53
|
+
thrift --gen rb:namespaced --recurse path/to/service.thrift
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Generated files are typically written to `gen-rb/` and can be required
|
|
57
|
+
directly from your application.
|
|
58
|
+
|
|
59
|
+
## Basic Client Usage
|
|
60
|
+
|
|
61
|
+
```ruby
|
|
62
|
+
$:.push File.expand_path('gen-rb', __dir__)
|
|
63
|
+
require 'thrift'
|
|
64
|
+
require 'calculator'
|
|
65
|
+
|
|
66
|
+
socket = Thrift::Socket.new('localhost', 9090)
|
|
67
|
+
transport = Thrift::BufferedTransport.new(socket)
|
|
68
|
+
protocol = Thrift::BinaryProtocol.new(transport)
|
|
69
|
+
client = Calculator::Client.new(protocol)
|
|
70
|
+
|
|
71
|
+
transport.open
|
|
72
|
+
puts client.add(1, 1)
|
|
73
|
+
transport.close
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## Basic Server Usage
|
|
77
|
+
|
|
78
|
+
```ruby
|
|
79
|
+
$:.push File.expand_path('gen-rb', __dir__)
|
|
80
|
+
require 'thrift'
|
|
81
|
+
require 'calculator'
|
|
82
|
+
|
|
83
|
+
class CalculatorHandler
|
|
84
|
+
def add(a, b)
|
|
85
|
+
a + b
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
handler = CalculatorHandler.new
|
|
90
|
+
processor = Calculator::Processor.new(handler)
|
|
91
|
+
server_transport = Thrift::ServerSocket.new(9090)
|
|
92
|
+
transport_factory = Thrift::BufferedTransportFactory.new
|
|
93
|
+
protocol_factory = Thrift::BinaryProtocolFactory.new
|
|
94
|
+
|
|
95
|
+
server = Thrift::ThreadedServer.new(processor, server_transport,
|
|
96
|
+
transport_factory, protocol_factory)
|
|
97
|
+
server.serve
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
## Development and Tests
|
|
101
|
+
|
|
102
|
+
- `bundle exec rake spec` runs the Ruby specs. It expects a built Thrift
|
|
103
|
+
compiler at `../../compiler/cpp/thrift`.
|
|
104
|
+
- `bundle exec rake test` runs the cross-language test suite; it must be
|
|
105
|
+
executed from a full Thrift checkout.
|
|
106
|
+
- `bundle exec rake build_ext` (implicit in the tasks above) compiles the
|
|
107
|
+
optional native extension that accelerates protocols and buffers.
|
|
108
|
+
|
|
109
|
+
## More Ruby Code
|
|
110
|
+
|
|
111
|
+
- Tutorial client and server: `tutorial/rb/RubyClient.rb` and `tutorial/rb/RubyServer.rb`
|
|
112
|
+
- Runtime benchmarks: `lib/rb/benchmark`
|
|
113
|
+
- Protocol benchmark: `test/rb/benchmarks/protocol_benchmark.rb`
|
|
114
|
+
- Library specs: `lib/rb/spec`
|
|
115
|
+
- Fuzzing harnesses and notes: `lib/rb/test/fuzz`
|
|
116
|
+
- Cross-language and integration tests: `test/rb`
|
|
117
|
+
|
|
118
|
+
## Breaking Changes
|
|
119
|
+
|
|
120
|
+
### 0.24.0
|
|
121
|
+
|
|
122
|
+
Connect timeout handling changed for both `Thrift::Socket` and
|
|
123
|
+
`Thrift::SSLSocket`.
|
|
124
|
+
|
|
125
|
+
- `timeout == nil` and `timeout == 0` now use blocking connect/open semantics.
|
|
126
|
+
Older releases already treated `nil` that way, but treated `0` differently
|
|
127
|
+
across operations: `read` and `write` used the blocking path, plain TCP
|
|
128
|
+
`open` used a zero-length poll, and TLS `open` could spin in the handshake
|
|
129
|
+
retry loop.
|
|
130
|
+
- Positive timeouts now bound the whole connect/open operation instead of
|
|
131
|
+
effectively applying a fresh timeout window at each wait or address attempt.
|
|
132
|
+
For plain TCP this budget is shared across address fallback. For TLS it is
|
|
133
|
+
shared across the TCP connect and the SSL handshake.
|
|
134
|
+
- Connect/open timeout expiry now raises
|
|
135
|
+
`Thrift::TransportException::TIMED_OUT`. Older releases could report the same
|
|
136
|
+
condition as `NOT_OPEN`, and `Thrift::SSLSocket` could keep retrying the
|
|
137
|
+
handshake after the wait timed out.
|
|
138
|
+
|
|
139
|
+
If your application matched `NOT_OPEN` for connect timeout handling, update it
|
|
140
|
+
to handle `TIMED_OUT`. If you relied on `timeout = 0` meaning immediate failure
|
|
141
|
+
or on repeated retries extending the effective timeout during TCP fallback or
|
|
142
|
+
TLS handshake, update those call paths before upgrading.
|
|
143
|
+
|
|
144
|
+
Ruby server socket transports now apply a 5-second timeout to accepted client
|
|
145
|
+
sockets by default. This prevents stalled clients from blocking server threads
|
|
146
|
+
indefinitely during response writes. Applications that intentionally require
|
|
147
|
+
blocking accepted sockets can pass `client_timeout: nil` or `client_timeout: 0`
|
|
148
|
+
when constructing `Thrift::ServerSocket`, `Thrift::SSLServerSocket`, or
|
|
149
|
+
`Thrift::UNIXServerSocket`.
|
|
150
|
+
|
|
151
|
+
Generated Ruby structs and unions now suffix field ID constants as
|
|
152
|
+
`*_FIELD_ID` instead of exposing bare uppercased field names. For example,
|
|
153
|
+
`MyStruct::FOO` becomes `MyStruct::FOO_FIELD_ID`. This avoids collisions with
|
|
154
|
+
the generated `FIELDS` metadata hash for field names such as `fields`, but it
|
|
155
|
+
is a source-compatible break if your application referenced the old constants
|
|
156
|
+
directly. Regenerate Ruby code and update those constant references atomically.
|
|
157
|
+
|
|
158
|
+
Ruby binary protocol writers now enforce signed Thrift integer ranges before
|
|
159
|
+
serializing values. `byte`, `i16`, `i32`, and `i64` writes reject values outside
|
|
160
|
+
their declared signed ranges, and binary/string/container sizes must fit in a
|
|
161
|
+
non-negative signed `i32` length. Older releases could silently wrap or clip
|
|
162
|
+
some out-of-range values, such as writing `255` as a byte that read back as
|
|
163
|
+
`-1`. This applies to both `Thrift::BinaryProtocol` and
|
|
164
|
+
`Thrift::BinaryProtocolAccelerated`.
|
|
165
|
+
|
|
166
|
+
### 0.23.0
|
|
167
|
+
|
|
168
|
+
The documented source-build flow now effectively requires Ruby `2.7+`.
|
|
169
|
+
The committed development bundle no longer resolves on Ruby `2.6`
|
|
170
|
+
(`json-2.18.1 requires ruby version >= 2.7`), so building and testing this
|
|
171
|
+
library from source should be treated as `2.7+`.
|
|
172
|
+
|
|
173
|
+
Generated structs and unions now consistently raise
|
|
174
|
+
`Thrift::ProtocolException::INVALID_DATA` for invalid payloads such as unset
|
|
175
|
+
required fields, invalid enum values, or invalid union state. If your
|
|
176
|
+
application or tests matched older exception types or messages, update them.
|
|
177
|
+
|
|
178
|
+
Regenerated Ruby clients now validate replies more strictly. Mismatched reply
|
|
179
|
+
message types, method names, or sequence IDs raise
|
|
180
|
+
`Thrift::ApplicationException::INVALID_MESSAGE_TYPE`,
|
|
181
|
+
`Thrift::ApplicationException::WRONG_METHOD_NAME`, or
|
|
182
|
+
`Thrift::ApplicationException::BAD_SEQUENCE_ID`. If you relied on older,
|
|
183
|
+
looser reply handling in servers, proxies, or tests, regenerate and update
|
|
184
|
+
those call paths together.
|
|
185
|
+
|
|
186
|
+
Generated Ruby clients have never been safe to share across concurrent
|
|
187
|
+
threads. A client tracks pending sequence IDs on a single reply stream, so use
|
|
188
|
+
one client/transport pair per thread or serialize access yourself.
|
|
189
|
+
|
|
190
|
+
Treat `Thrift::ApplicationException::BAD_SEQUENCE_ID` as a correctness bug
|
|
191
|
+
that needs immediate attention. It means the client read a reply whose
|
|
192
|
+
sequence ID did not match the next pending request, so the connection may
|
|
193
|
+
already be out of sync and you may be reading a reply intended for a
|
|
194
|
+
different call. The most common cause is sharing one client across threads,
|
|
195
|
+
but a buggy proxy or server can also cause it.
|
|
196
|
+
|
|
197
|
+
### 0.13.0
|
|
198
|
+
|
|
199
|
+
Ruby development and CI moved to Ruby `2.4+`, but the runtime still claimed
|
|
200
|
+
support for older interpreters. Treat Ruby `< 2.4` on the `0.13.x` line as
|
|
201
|
+
best-effort, not guaranteed.
|
|
202
|
+
|
|
203
|
+
- Historical note for very old releases: the Ruby runtime was rearranged to use
|
|
204
|
+
more Ruby-like names, and generated files switched to underscored filenames.
|
|
205
|
+
If you are upgrading very old code, regenerate your Ruby bindings and update
|
|
206
|
+
any old `T*` constants or legacy require paths such as
|
|
207
|
+
`TBinaryProtocol` -> `Thrift::BinaryProtocol`.
|
|
208
|
+
- `rb:namespaced` changes the generated file layout. Flat output from
|
|
209
|
+
`thrift --gen rb` and namespaced output from `thrift --gen rb:namespaced`
|
|
210
|
+
use different require paths, so switch them atomically with regenerated code.
|
|
211
|
+
|
|
212
|
+
```ruby
|
|
213
|
+
# --gen rb
|
|
214
|
+
require 'calculator'
|
|
215
|
+
|
|
216
|
+
# --gen rb:namespaced
|
|
217
|
+
require 'my_namespace/calculator'
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
## Migration Notes
|
|
221
|
+
|
|
222
|
+
- If you upgrade to `0.24.0`, treat `timeout` on `Thrift::Socket` and
|
|
223
|
+
`Thrift::SSLSocket` as one budget for the whole open path. For
|
|
224
|
+
`Thrift::SSLSocket`, that includes both the TCP connect and the TLS
|
|
225
|
+
handshake.
|
|
226
|
+
- If you upgrade to `0.24.0`, handle connect/open timeout expiry as
|
|
227
|
+
`Thrift::TransportException::TIMED_OUT` instead of `NOT_OPEN`.
|
|
228
|
+
- If you upgrade across the stricter reply-validation changes, regenerate all
|
|
229
|
+
Ruby stubs and deploy them with the matching Ruby runtime. Do not mix old
|
|
230
|
+
generated code, new generated code, and new runtime code on the same client
|
|
231
|
+
path without testing that combination.
|
|
232
|
+
- If you receive `Thrift::ApplicationException::BAD_SEQUENCE_ID`, treat the
|
|
233
|
+
connection as out of sync. Close it, create a new client/transport pair, and
|
|
234
|
+
investigate the root cause before retrying.
|
|
235
|
+
- Do not share one generated Ruby client across concurrent threads. Use one
|
|
236
|
+
client/transport pair per thread, or serialize access to a shared client.
|
|
237
|
+
- If you switch between `thrift --gen rb` and `thrift --gen rb:namespaced`,
|
|
238
|
+
regenerate all Ruby output and update `require` paths in the same change.
|
|
239
|
+
|
|
240
|
+
## Runtime Notes
|
|
241
|
+
|
|
242
|
+
- Loading the `thrift_native` extension changes which implementation you are
|
|
243
|
+
running. It replaces
|
|
244
|
+
`Thrift::Struct`, `Thrift::Union`, and `Thrift::CompactProtocol` methods
|
|
245
|
+
with C implementations in place. `Thrift::BinaryProtocol` remains available
|
|
246
|
+
in pure Ruby, and the C-backed binary protocol is opt-in through
|
|
247
|
+
`Thrift::BinaryProtocolAcceleratedFactory` or
|
|
248
|
+
`Thrift::BinaryProtocolAccelerated` when that class is available.
|
|
249
|
+
- The native extension is optional. If it cannot be built or loaded, Thrift
|
|
250
|
+
falls back to the pure-Ruby implementation. This mainly changes performance
|
|
251
|
+
and implementation details.
|
|
252
|
+
- JRuby skips the native extension automatically and uses the pure-Ruby path.
|
|
253
|
+
- Do not share one client instance across concurrent threads. A client tracks
|
|
254
|
+
request and reply state on a single transport stream.
|
|
255
|
+
- `Thrift::NonblockingServer` expects framed input. Use
|
|
256
|
+
`Thrift::FramedTransport` with it on the wire.
|
|
257
|
+
- Client and server must agree on transport and protocol choices. If you
|
|
258
|
+
switch to SSL, HTTP, header transport, compact protocol, or namespaced
|
|
259
|
+
generated code, update both ends together.
|
|
260
|
+
- HTTPS client transport verifies peers by default, and `Thrift::SSLSocket`
|
|
261
|
+
performs a hostname check against the host you pass in.
|
data/benchmark/benchmark.rb
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
1
2
|
#
|
|
2
3
|
# Licensed to the Apache Software Foundation (ASF) under one
|
|
3
4
|
# or more contributor license agreements. See the NOTICE file
|
|
@@ -19,6 +20,7 @@
|
|
|
19
20
|
|
|
20
21
|
require 'rubygems'
|
|
21
22
|
$:.unshift File.dirname(__FILE__) + '/../lib'
|
|
23
|
+
$:.unshift File.dirname(__FILE__) + '/../ext'
|
|
22
24
|
require 'thrift'
|
|
23
25
|
require 'stringio'
|
|
24
26
|
|
|
@@ -34,18 +36,21 @@ class Server
|
|
|
34
36
|
attr_accessor :interpreter
|
|
35
37
|
attr_accessor :host
|
|
36
38
|
attr_accessor :port
|
|
39
|
+
attr_accessor :protocol_type
|
|
37
40
|
|
|
38
41
|
def initialize(opts)
|
|
39
42
|
@serverclass = opts.fetch(:class, Thrift::NonblockingServer)
|
|
40
43
|
@interpreter = opts.fetch(:interpreter, "ruby")
|
|
41
44
|
@host = opts.fetch(:host, ::HOST)
|
|
42
45
|
@port = opts.fetch(:port, ::PORT)
|
|
46
|
+
@protocol_type = opts.fetch(:protocol_type, 'binary')
|
|
47
|
+
@tls = opts.fetch(:tls, false)
|
|
43
48
|
end
|
|
44
49
|
|
|
45
50
|
def start
|
|
46
51
|
return if @serverclass == Object
|
|
47
52
|
args = (File.basename(@interpreter) == "jruby" ? "-J-server" : "")
|
|
48
|
-
@pipe = IO.popen("#{@interpreter} #{args} #{File.dirname(__FILE__)}/server.rb #{@host} #{@port} #{@serverclass.name}", "r+")
|
|
53
|
+
@pipe = IO.popen("#{@interpreter} #{args} #{File.dirname(__FILE__)}/server.rb #{"-tls" if @tls} #{@host} #{@port} #{@serverclass.name} #{@protocol_type}", "r+")
|
|
49
54
|
Marshal.load(@pipe) # wait until the server has started
|
|
50
55
|
sleep 0.4 # give the server time to actually start spawning sockets
|
|
51
56
|
end
|
|
@@ -75,6 +80,8 @@ class BenchmarkManager
|
|
|
75
80
|
@interpreter = opts.fetch(:interpreter, "ruby")
|
|
76
81
|
@server = server
|
|
77
82
|
@log_exceptions = opts.fetch(:log_exceptions, false)
|
|
83
|
+
@protocol_type = opts.fetch(:protocol_type, 'binary')
|
|
84
|
+
@tls = opts.fetch(:tls, false)
|
|
78
85
|
end
|
|
79
86
|
|
|
80
87
|
def run
|
|
@@ -93,13 +100,15 @@ class BenchmarkManager
|
|
|
93
100
|
end
|
|
94
101
|
|
|
95
102
|
def spawn
|
|
96
|
-
pipe = IO.popen("#{@interpreter} #{File.dirname(__FILE__)}/client.rb #{"-log-exceptions" if @log_exceptions} #{@host} #{@port} #{@clients_per_process} #{@calls_per_client}")
|
|
103
|
+
pipe = IO.popen("#{@interpreter} #{File.dirname(__FILE__)}/client.rb #{"-log-exceptions" if @log_exceptions} #{"-tls" if @tls} #{@host} #{@port} #{@clients_per_process} #{@calls_per_client} #{@protocol_type}")
|
|
97
104
|
@pool << pipe
|
|
98
105
|
end
|
|
99
106
|
|
|
100
107
|
def socket_class
|
|
101
108
|
if @socket
|
|
102
109
|
Thrift::UNIXSocket
|
|
110
|
+
elsif @tls
|
|
111
|
+
Thrift::SSLSocket
|
|
103
112
|
else
|
|
104
113
|
Thrift::Socket
|
|
105
114
|
end
|
|
@@ -108,7 +117,7 @@ class BenchmarkManager
|
|
|
108
117
|
def collect_output
|
|
109
118
|
puts "Collecting output..."
|
|
110
119
|
# read from @pool until all sockets are closed
|
|
111
|
-
@buffers = Hash.new { |h,k| h[k] = '' }
|
|
120
|
+
@buffers = Hash.new { |h, k| h[k] = ''.b }
|
|
112
121
|
until @pool.empty?
|
|
113
122
|
rd, = select(@pool)
|
|
114
123
|
next if rd.nil?
|
|
@@ -176,9 +185,9 @@ class BenchmarkManager
|
|
|
176
185
|
end
|
|
177
186
|
end
|
|
178
187
|
@report = {}
|
|
179
|
-
@report[:total_calls] = call_times.inject(0.0) { |a,t| a += t }
|
|
188
|
+
@report[:total_calls] = call_times.inject(0.0) { |a, t| a += t }
|
|
180
189
|
@report[:avg_calls] = @report[:total_calls] / call_times.size
|
|
181
|
-
@report[:total_clients] = client_times.inject(0.0) { |a,t| a += t }
|
|
190
|
+
@report[:total_clients] = client_times.inject(0.0) { |a, t| a += t }
|
|
182
191
|
@report[:avg_clients] = @report[:total_clients] / client_times.size
|
|
183
192
|
@report[:connection_failures] = connection_failures.size
|
|
184
193
|
@report[:connection_errors] = connection_errors.size
|
|
@@ -197,6 +206,7 @@ class BenchmarkManager
|
|
|
197
206
|
[["Server class", "%s"], @server.serverclass == Object ? "" : @server.serverclass],
|
|
198
207
|
[["Server interpreter", "%s"], @server.interpreter],
|
|
199
208
|
[["Client interpreter", "%s"], @interpreter],
|
|
209
|
+
[["Protocol type", "%s"], @protocol_type],
|
|
200
210
|
[["Socket class", "%s"], socket_class],
|
|
201
211
|
["Number of processes", @num_processes],
|
|
202
212
|
["Clients per process", @clients_per_process],
|
|
@@ -232,8 +242,8 @@ class BenchmarkManager
|
|
|
232
242
|
|
|
233
243
|
def tabulate(fmt, *labels_and_values)
|
|
234
244
|
labels = labels_and_values.map { |l| Array === l ? l.first : l }
|
|
235
|
-
label_width = labels.inject(0) { |w,l| l.size > w ? l.size : w }
|
|
236
|
-
labels_and_values.each do |(l,v)|
|
|
245
|
+
label_width = labels.inject(0) { |w, l| l.size > w ? l.size : w }
|
|
246
|
+
labels_and_values.each do |(l, v)|
|
|
237
247
|
f = fmt
|
|
238
248
|
l, f, c = l if Array === l
|
|
239
249
|
fmtstr = "%-#{label_width+1}s #{f}"
|
|
@@ -246,26 +256,31 @@ class BenchmarkManager
|
|
|
246
256
|
end
|
|
247
257
|
|
|
248
258
|
def resolve_const(const)
|
|
249
|
-
const and const.split('::').inject(Object) { |k,c| k.const_get(c) }
|
|
259
|
+
const and const.split('::').inject(Object) { |k, c| k.const_get(c) }
|
|
250
260
|
end
|
|
251
261
|
|
|
252
262
|
puts "Starting server..."
|
|
263
|
+
protocol_type = ENV['THRIFT_PROTOCOL'] || 'binary'
|
|
253
264
|
args = {}
|
|
254
265
|
args[:interpreter] = ENV['THRIFT_SERVER_INTERPRETER'] || ENV['THRIFT_INTERPRETER'] || "ruby"
|
|
255
266
|
args[:class] = resolve_const(ENV['THRIFT_SERVER']) || Thrift::NonblockingServer
|
|
256
267
|
args[:host] = ENV['THRIFT_HOST'] || HOST
|
|
257
268
|
args[:port] = (ENV['THRIFT_PORT'] || PORT).to_i
|
|
269
|
+
args[:tls] = ENV['THRIFT_TLS'] == 'true'
|
|
270
|
+
args[:protocol_type] = protocol_type
|
|
258
271
|
server = Server.new(args)
|
|
259
272
|
server.start
|
|
260
273
|
|
|
261
274
|
args = {}
|
|
262
275
|
args[:host] = ENV['THRIFT_HOST'] || HOST
|
|
263
276
|
args[:port] = (ENV['THRIFT_PORT'] || PORT).to_i
|
|
277
|
+
args[:tls] = ENV['THRIFT_TLS'] == 'true'
|
|
264
278
|
args[:num_processes] = (ENV['THRIFT_NUM_PROCESSES'] || 40).to_i
|
|
265
279
|
args[:clients_per_process] = (ENV['THRIFT_NUM_CLIENTS'] || 5).to_i
|
|
266
280
|
args[:calls_per_client] = (ENV['THRIFT_NUM_CALLS'] || 50).to_i
|
|
267
281
|
args[:interpreter] = ENV['THRIFT_CLIENT_INTERPRETER'] || ENV['THRIFT_INTERPRETER'] || "ruby"
|
|
268
282
|
args[:log_exceptions] = !!ENV['THRIFT_LOG_EXCEPTIONS']
|
|
283
|
+
args[:protocol_type] = protocol_type
|
|
269
284
|
BenchmarkManager.new(args, server).run
|
|
270
285
|
|
|
271
286
|
server.shutdown
|
data/benchmark/client.rb
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
1
2
|
#
|
|
2
3
|
# Licensed to the Apache Software Foundation (ASF) under one
|
|
3
4
|
# or more contributor license agreements. See the NOTICE file
|
|
@@ -18,24 +19,66 @@
|
|
|
18
19
|
#
|
|
19
20
|
|
|
20
21
|
$:.unshift File.dirname(__FILE__) + '/../lib'
|
|
22
|
+
$:.unshift File.dirname(__FILE__) + '/../ext'
|
|
21
23
|
require 'thrift'
|
|
24
|
+
require 'openssl'
|
|
22
25
|
$:.unshift File.dirname(__FILE__) + "/gen-rb"
|
|
23
26
|
require 'benchmark_service'
|
|
24
27
|
|
|
25
28
|
class Client
|
|
26
|
-
def initialize(host, port, clients_per_process, calls_per_client, log_exceptions)
|
|
29
|
+
def initialize(host, port, clients_per_process, calls_per_client, log_exceptions, tls, protocol_type)
|
|
27
30
|
@host = host
|
|
28
31
|
@port = port
|
|
29
32
|
@clients_per_process = clients_per_process
|
|
30
33
|
@calls_per_client = calls_per_client
|
|
31
34
|
@log_exceptions = log_exceptions
|
|
35
|
+
@tls = tls
|
|
36
|
+
@protocol_type = protocol_type || 'binary'
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def create_protocol(socket)
|
|
40
|
+
case @protocol_type
|
|
41
|
+
when 'binary'
|
|
42
|
+
transport = Thrift::FramedTransport.new(socket)
|
|
43
|
+
Thrift::BinaryProtocol.new(transport)
|
|
44
|
+
when 'compact'
|
|
45
|
+
transport = Thrift::FramedTransport.new(socket)
|
|
46
|
+
Thrift::CompactProtocol.new(transport)
|
|
47
|
+
when 'header'
|
|
48
|
+
Thrift::HeaderProtocol.new(socket)
|
|
49
|
+
when 'header-compact'
|
|
50
|
+
Thrift::HeaderProtocol.new(socket, nil, Thrift::HeaderSubprotocolID::COMPACT)
|
|
51
|
+
when 'header-zlib'
|
|
52
|
+
protocol = Thrift::HeaderProtocol.new(socket)
|
|
53
|
+
protocol.add_transform(Thrift::HeaderTransformID::ZLIB)
|
|
54
|
+
protocol
|
|
55
|
+
else
|
|
56
|
+
transport = Thrift::FramedTransport.new(socket)
|
|
57
|
+
Thrift::BinaryProtocol.new(transport)
|
|
58
|
+
end
|
|
32
59
|
end
|
|
33
60
|
|
|
34
61
|
def run
|
|
35
62
|
@clients_per_process.times do
|
|
36
|
-
socket =
|
|
37
|
-
|
|
38
|
-
|
|
63
|
+
socket = if @tls
|
|
64
|
+
ssl_context = OpenSSL::SSL::SSLContext.new.tap do |ctx|
|
|
65
|
+
ctx.verify_mode = OpenSSL::SSL::VERIFY_PEER
|
|
66
|
+
ctx.min_version = OpenSSL::SSL::TLS1_2_VERSION
|
|
67
|
+
|
|
68
|
+
keys_dir = File.expand_path("../../../test/keys", __dir__)
|
|
69
|
+
ctx.ca_file = File.join(keys_dir, "CA.pem")
|
|
70
|
+
ctx.cert = OpenSSL::X509::Certificate.new(File.open(File.join(keys_dir, "client.crt")))
|
|
71
|
+
ctx.cert_store = OpenSSL::X509::Store.new
|
|
72
|
+
ctx.cert_store.add_file(File.join(keys_dir, 'server.pem'))
|
|
73
|
+
ctx.key = OpenSSL::PKey::RSA.new(File.open(File.join(keys_dir, "client.key")))
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
Thrift::SSLSocket.new(@host, @port, 5, ssl_context)
|
|
77
|
+
else
|
|
78
|
+
Thrift::Socket.new(@host, @port, 5)
|
|
79
|
+
end
|
|
80
|
+
protocol = create_protocol(socket)
|
|
81
|
+
transport = protocol.trans
|
|
39
82
|
client = ThriftBenchmark::BenchmarkService::Client.new(protocol)
|
|
40
83
|
begin
|
|
41
84
|
start = Time.now
|
|
@@ -68,7 +111,8 @@ class Client
|
|
|
68
111
|
end
|
|
69
112
|
|
|
70
113
|
log_exceptions = true if ARGV[0] == '-log-exceptions' and ARGV.shift
|
|
114
|
+
tls = true if ARGV[0] == '-tls' and ARGV.shift
|
|
71
115
|
|
|
72
|
-
host, port, clients_per_process, calls_per_client = ARGV
|
|
116
|
+
host, port, clients_per_process, calls_per_client, protocol_type = ARGV
|
|
73
117
|
|
|
74
|
-
Client.new(host, port.to_i, clients_per_process.to_i, calls_per_client.to_i, log_exceptions).run
|
|
118
|
+
Client.new(host, port.to_i, clients_per_process.to_i, calls_per_client.to_i, log_exceptions, tls, protocol_type).run
|
data/benchmark/server.rb
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
1
2
|
#
|
|
2
3
|
# Licensed to the Apache Software Foundation (ASF) under one
|
|
3
4
|
# or more contributor license agreements. See the NOTICE file
|
|
@@ -18,7 +19,9 @@
|
|
|
18
19
|
#
|
|
19
20
|
|
|
20
21
|
$:.unshift File.dirname(__FILE__) + '/../lib'
|
|
22
|
+
$:.unshift File.dirname(__FILE__) + '/../ext'
|
|
21
23
|
require 'thrift'
|
|
24
|
+
require 'openssl'
|
|
22
25
|
$:.unshift File.dirname(__FILE__) + "/gen-rb"
|
|
23
26
|
require 'benchmark_service'
|
|
24
27
|
|
|
@@ -36,12 +39,46 @@ module Server
|
|
|
36
39
|
end
|
|
37
40
|
end
|
|
38
41
|
|
|
39
|
-
def self.
|
|
42
|
+
def self.create_factories(protocol_type)
|
|
43
|
+
case protocol_type
|
|
44
|
+
when 'binary'
|
|
45
|
+
[FramedTransportFactory.new, BinaryProtocolFactory.new]
|
|
46
|
+
when 'compact'
|
|
47
|
+
[FramedTransportFactory.new, CompactProtocolFactory.new]
|
|
48
|
+
when 'header'
|
|
49
|
+
[HeaderTransportFactory.new, HeaderProtocolFactory.new]
|
|
50
|
+
when 'header-compact'
|
|
51
|
+
[HeaderTransportFactory.new, HeaderProtocolFactory.new(nil, HeaderSubprotocolID::COMPACT)]
|
|
52
|
+
when 'header-zlib'
|
|
53
|
+
# Note: Server doesn't add transforms - it mirrors client's transforms
|
|
54
|
+
[HeaderTransportFactory.new, HeaderProtocolFactory.new]
|
|
55
|
+
else
|
|
56
|
+
[FramedTransportFactory.new, BinaryProtocolFactory.new]
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def self.start_server(host, port, serverClass, tls, protocol_type = nil)
|
|
40
61
|
handler = BenchmarkHandler.new
|
|
41
62
|
processor = ThriftBenchmark::BenchmarkService::Processor.new(handler)
|
|
42
|
-
transport =
|
|
43
|
-
|
|
44
|
-
|
|
63
|
+
transport = if tls
|
|
64
|
+
ssl_context = OpenSSL::SSL::SSLContext.new.tap do |ctx|
|
|
65
|
+
ctx.verify_mode = OpenSSL::SSL::VERIFY_PEER
|
|
66
|
+
ctx.min_version = OpenSSL::SSL::TLS1_2_VERSION
|
|
67
|
+
|
|
68
|
+
keys_dir = File.expand_path("../../../test/keys", __dir__)
|
|
69
|
+
ctx.ca_file = File.join(keys_dir, "CA.pem")
|
|
70
|
+
ctx.cert = OpenSSL::X509::Certificate.new(File.open(File.join(keys_dir, "server.crt")))
|
|
71
|
+
ctx.cert_store = OpenSSL::X509::Store.new
|
|
72
|
+
ctx.cert_store.add_file(File.join(keys_dir, 'client.pem'))
|
|
73
|
+
ctx.key = OpenSSL::PKey::RSA.new(File.open(File.join(keys_dir, "server.key")))
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
Thrift::SSLServerSocket.new(host, port, ssl_context)
|
|
77
|
+
else
|
|
78
|
+
ServerSocket.new(host, port)
|
|
79
|
+
end
|
|
80
|
+
transport_factory, protocol_factory = create_factories(protocol_type || 'binary')
|
|
81
|
+
args = [processor, transport, transport_factory, protocol_factory, 20]
|
|
45
82
|
if serverClass == NonblockingServer
|
|
46
83
|
logger = Logger.new(STDERR)
|
|
47
84
|
logger.level = Logger::WARN
|
|
@@ -65,12 +102,14 @@ module Server
|
|
|
65
102
|
end
|
|
66
103
|
|
|
67
104
|
def resolve_const(const)
|
|
68
|
-
const and const.split('::').inject(Object) { |k,c| k.const_get(c) }
|
|
105
|
+
const and const.split('::').inject(Object) { |k, c| k.const_get(c) }
|
|
69
106
|
end
|
|
70
107
|
|
|
71
|
-
|
|
108
|
+
tls = true if ARGV[0] == '-tls' and ARGV.shift
|
|
109
|
+
|
|
110
|
+
host, port, serverklass, protocol_type = ARGV
|
|
72
111
|
|
|
73
|
-
Server.start_server(host, port.to_i, resolve_const(serverklass))
|
|
112
|
+
Server.start_server(host, port.to_i, resolve_const(serverklass), tls, protocol_type)
|
|
74
113
|
|
|
75
114
|
# let our host know that the interpreter has started
|
|
76
115
|
# ideally we'd wait until the server was serving, but we don't have a hook for that
|
data/benchmark/thin_server.rb
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
1
2
|
#
|
|
2
3
|
# Licensed to the Apache Software Foundation (ASF) under one
|
|
3
4
|
# or more contributor license agreements. See the NOTICE file
|
|
@@ -18,6 +19,7 @@
|
|
|
18
19
|
#
|
|
19
20
|
|
|
20
21
|
$:.unshift File.dirname(__FILE__) + '/../lib'
|
|
22
|
+
$:.unshift File.dirname(__FILE__) + '/../ext'
|
|
21
23
|
require 'thrift'
|
|
22
24
|
$:.unshift File.dirname(__FILE__) + "/gen-rb"
|
|
23
25
|
require 'benchmark_service'
|