upfluence-thrift 1.0.1
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 +7 -0
- data/README.md +43 -0
- data/benchmark/Benchmark.thrift +24 -0
- data/benchmark/benchmark.rb +271 -0
- data/benchmark/client.rb +74 -0
- data/benchmark/gen-rb/benchmark_constants.rb +11 -0
- data/benchmark/gen-rb/benchmark_service.rb +80 -0
- data/benchmark/gen-rb/benchmark_types.rb +10 -0
- data/benchmark/server.rb +82 -0
- data/benchmark/thin_server.rb +44 -0
- data/ext/binary_protocol_accelerated.c +460 -0
- data/ext/binary_protocol_accelerated.h +20 -0
- data/ext/bytes.c +36 -0
- data/ext/bytes.h +31 -0
- data/ext/compact_protocol.c +637 -0
- data/ext/compact_protocol.h +20 -0
- data/ext/constants.h +99 -0
- data/ext/extconf.rb +34 -0
- data/ext/macros.h +41 -0
- data/ext/memory_buffer.c +134 -0
- data/ext/memory_buffer.h +20 -0
- data/ext/protocol.c +0 -0
- data/ext/protocol.h +0 -0
- data/ext/strlcpy.c +41 -0
- data/ext/strlcpy.h +34 -0
- data/ext/struct.c +707 -0
- data/ext/struct.h +25 -0
- data/ext/thrift_native.c +201 -0
- data/lib/thrift.rb +68 -0
- data/lib/thrift/bytes.rb +131 -0
- data/lib/thrift/client.rb +71 -0
- data/lib/thrift/core_ext.rb +23 -0
- data/lib/thrift/core_ext/fixnum.rb +29 -0
- data/lib/thrift/exceptions.rb +87 -0
- data/lib/thrift/multiplexed_processor.rb +76 -0
- data/lib/thrift/processor.rb +57 -0
- data/lib/thrift/protocol/base_protocol.rb +379 -0
- data/lib/thrift/protocol/binary_protocol.rb +237 -0
- data/lib/thrift/protocol/binary_protocol_accelerated.rb +39 -0
- data/lib/thrift/protocol/compact_protocol.rb +435 -0
- data/lib/thrift/protocol/json_protocol.rb +769 -0
- data/lib/thrift/protocol/multiplexed_protocol.rb +40 -0
- data/lib/thrift/protocol/protocol_decorator.rb +194 -0
- data/lib/thrift/serializer/deserializer.rb +33 -0
- data/lib/thrift/serializer/serializer.rb +34 -0
- data/lib/thrift/server/base_server.rb +31 -0
- data/lib/thrift/server/mongrel_http_server.rb +60 -0
- data/lib/thrift/server/nonblocking_server.rb +305 -0
- data/lib/thrift/server/rack_application.rb +61 -0
- data/lib/thrift/server/simple_server.rb +43 -0
- data/lib/thrift/server/thin_http_server.rb +51 -0
- data/lib/thrift/server/thread_pool_server.rb +75 -0
- data/lib/thrift/server/threaded_server.rb +47 -0
- data/lib/thrift/struct.rb +237 -0
- data/lib/thrift/struct_union.rb +192 -0
- data/lib/thrift/thrift_native.rb +24 -0
- data/lib/thrift/transport/base_server_transport.rb +37 -0
- data/lib/thrift/transport/base_transport.rb +109 -0
- data/lib/thrift/transport/buffered_transport.rb +114 -0
- data/lib/thrift/transport/framed_transport.rb +117 -0
- data/lib/thrift/transport/http_client_transport.rb +56 -0
- data/lib/thrift/transport/io_stream_transport.rb +39 -0
- data/lib/thrift/transport/memory_buffer_transport.rb +125 -0
- data/lib/thrift/transport/server_socket.rb +63 -0
- data/lib/thrift/transport/socket.rb +139 -0
- data/lib/thrift/transport/unix_server_socket.rb +60 -0
- data/lib/thrift/transport/unix_socket.rb +40 -0
- data/lib/thrift/types.rb +101 -0
- data/lib/thrift/union.rb +179 -0
- data/spec/BaseService.thrift +27 -0
- data/spec/ExtendedService.thrift +25 -0
- data/spec/Referenced.thrift +44 -0
- data/spec/ThriftNamespacedSpec.thrift +53 -0
- data/spec/ThriftSpec.thrift +183 -0
- data/spec/base_protocol_spec.rb +217 -0
- data/spec/base_transport_spec.rb +350 -0
- data/spec/binary_protocol_accelerated_spec.rb +42 -0
- data/spec/binary_protocol_spec.rb +66 -0
- data/spec/binary_protocol_spec_shared.rb +455 -0
- data/spec/bytes_spec.rb +160 -0
- data/spec/client_spec.rb +99 -0
- data/spec/compact_protocol_spec.rb +143 -0
- data/spec/exception_spec.rb +141 -0
- data/spec/flat_spec.rb +62 -0
- data/spec/gen-rb/base/base_service.rb +80 -0
- data/spec/gen-rb/base/base_service_constants.rb +11 -0
- data/spec/gen-rb/base/base_service_types.rb +26 -0
- data/spec/gen-rb/extended/extended_service.rb +78 -0
- data/spec/gen-rb/extended/extended_service_constants.rb +11 -0
- data/spec/gen-rb/extended/extended_service_types.rb +12 -0
- data/spec/gen-rb/flat/namespaced_nonblocking_service.rb +272 -0
- data/spec/gen-rb/flat/referenced_constants.rb +11 -0
- data/spec/gen-rb/flat/referenced_types.rb +17 -0
- data/spec/gen-rb/flat/thrift_namespaced_spec_constants.rb +11 -0
- data/spec/gen-rb/flat/thrift_namespaced_spec_types.rb +28 -0
- data/spec/gen-rb/namespaced_spec_namespace/namespaced_nonblocking_service.rb +272 -0
- data/spec/gen-rb/namespaced_spec_namespace/thrift_namespaced_spec_constants.rb +11 -0
- data/spec/gen-rb/namespaced_spec_namespace/thrift_namespaced_spec_types.rb +28 -0
- data/spec/gen-rb/nonblocking_service.rb +272 -0
- data/spec/gen-rb/other_namespace/referenced_constants.rb +11 -0
- data/spec/gen-rb/other_namespace/referenced_types.rb +17 -0
- data/spec/gen-rb/thrift_spec_constants.rb +11 -0
- data/spec/gen-rb/thrift_spec_types.rb +538 -0
- data/spec/http_client_spec.rb +120 -0
- data/spec/json_protocol_spec.rb +513 -0
- data/spec/namespaced_spec.rb +67 -0
- data/spec/nonblocking_server_spec.rb +263 -0
- data/spec/processor_spec.rb +80 -0
- data/spec/serializer_spec.rb +67 -0
- data/spec/server_socket_spec.rb +79 -0
- data/spec/server_spec.rb +147 -0
- data/spec/socket_spec.rb +61 -0
- data/spec/socket_spec_shared.rb +104 -0
- data/spec/spec_helper.rb +64 -0
- data/spec/struct_nested_containers_spec.rb +191 -0
- data/spec/struct_spec.rb +293 -0
- data/spec/thin_http_server_spec.rb +141 -0
- data/spec/types_spec.rb +115 -0
- data/spec/union_spec.rb +203 -0
- data/spec/unix_socket_spec.rb +107 -0
- data/test/debug_proto/gen-rb/debug_proto_test_constants.rb +274 -0
- data/test/debug_proto/gen-rb/debug_proto_test_types.rb +761 -0
- data/test/debug_proto/gen-rb/empty_service.rb +24 -0
- data/test/debug_proto/gen-rb/inherited.rb +79 -0
- data/test/debug_proto/gen-rb/reverse_order_service.rb +82 -0
- data/test/debug_proto/gen-rb/service_for_exception_with_a_map.rb +81 -0
- data/test/debug_proto/gen-rb/srv.rb +330 -0
- metadata +388 -0
@@ -0,0 +1,40 @@
|
|
1
|
+
#
|
2
|
+
# Licensed to the Apache Software Foundation (ASF) under one
|
3
|
+
# or more contributor license agreements. See the NOTICE file
|
4
|
+
# distributed with this work for additional information
|
5
|
+
# regarding copyright ownership. The ASF licenses this file
|
6
|
+
# to you under the Apache License, Version 2.0 (the
|
7
|
+
# "License"); you may not use this file except in compliance
|
8
|
+
# with the License. You may obtain a copy of the License at
|
9
|
+
#
|
10
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
11
|
+
#
|
12
|
+
# Unless required by applicable law or agreed to in writing,
|
13
|
+
# software distributed under the License is distributed on an
|
14
|
+
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
15
|
+
# KIND, either express or implied. See the License for the
|
16
|
+
# specific language governing permissions and limitations
|
17
|
+
# under the License.
|
18
|
+
|
19
|
+
require 'thrift/protocol/protocol_decorator'
|
20
|
+
|
21
|
+
module Thrift
|
22
|
+
class MultiplexedProtocol < BaseProtocol
|
23
|
+
|
24
|
+
include ProtocolDecorator
|
25
|
+
|
26
|
+
def initialize(protocol, service_name)
|
27
|
+
super(protocol)
|
28
|
+
@service_name = service_name
|
29
|
+
end
|
30
|
+
|
31
|
+
def write_message_begin(name, type, seqid)
|
32
|
+
case type
|
33
|
+
when MessageTypes::CALL, MessageTypes::ONEWAY
|
34
|
+
@protocol.write_message_begin("#{@service_name}:#{name}", type, seqid)
|
35
|
+
else
|
36
|
+
@protocol.write_message_begin(name, type, seqid)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,194 @@
|
|
1
|
+
#
|
2
|
+
# Licensed to the Apache Software Foundation (ASF) under one
|
3
|
+
# or more contributor license agreements. See the NOTICE file
|
4
|
+
# distributed with this work for additional information
|
5
|
+
# regarding copyright ownership. The ASF licenses this file
|
6
|
+
# to you under the Apache License, Version 2.0 (the
|
7
|
+
# "License"); you may not use this file except in compliance
|
8
|
+
# with the License. You may obtain a copy of the License at
|
9
|
+
#
|
10
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
11
|
+
#
|
12
|
+
# Unless required by applicable law or agreed to in writing,
|
13
|
+
# software distributed under the License is distributed on an
|
14
|
+
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
15
|
+
# KIND, either express or implied. See the License for the
|
16
|
+
# specific language governing permissions and limitations
|
17
|
+
# under the License.
|
18
|
+
|
19
|
+
module Thrift
|
20
|
+
module ProtocolDecorator
|
21
|
+
|
22
|
+
def initialize(protocol)
|
23
|
+
@protocol = protocol
|
24
|
+
end
|
25
|
+
|
26
|
+
def trans
|
27
|
+
@protocol.trans
|
28
|
+
end
|
29
|
+
|
30
|
+
def write_message_begin(name, type, seqid)
|
31
|
+
@protocol.write_message_begin
|
32
|
+
end
|
33
|
+
|
34
|
+
def write_message_end
|
35
|
+
@protocol.write_message_end
|
36
|
+
end
|
37
|
+
|
38
|
+
def write_struct_begin(name)
|
39
|
+
@protocol.write_struct_begin(name)
|
40
|
+
end
|
41
|
+
|
42
|
+
def write_struct_end
|
43
|
+
@protocol.write_struct_end
|
44
|
+
end
|
45
|
+
|
46
|
+
def write_field_begin(name, type, id)
|
47
|
+
@protocol.write_field_begin(name, type, id)
|
48
|
+
end
|
49
|
+
|
50
|
+
def write_field_end
|
51
|
+
@protocol.write_field_end
|
52
|
+
end
|
53
|
+
|
54
|
+
def write_field_stop
|
55
|
+
@protocol.write_field_stop
|
56
|
+
end
|
57
|
+
|
58
|
+
def write_map_begin(ktype, vtype, size)
|
59
|
+
@protocol.write_map_begin(ktype, vtype, size)
|
60
|
+
end
|
61
|
+
|
62
|
+
def write_map_end
|
63
|
+
@protocol.write_map_end
|
64
|
+
end
|
65
|
+
|
66
|
+
def write_list_begin(etype, size)
|
67
|
+
@protocol.write_list_begin(etype, size)
|
68
|
+
end
|
69
|
+
|
70
|
+
def write_list_end
|
71
|
+
@protocol.write_list_end
|
72
|
+
end
|
73
|
+
|
74
|
+
def write_set_begin(etype, size)
|
75
|
+
@protocol.write_set_begin(etype, size)
|
76
|
+
end
|
77
|
+
|
78
|
+
def write_set_end
|
79
|
+
@protocol.write_set_end
|
80
|
+
end
|
81
|
+
|
82
|
+
def write_bool(bool)
|
83
|
+
@protocol.write_bool(bool)
|
84
|
+
end
|
85
|
+
|
86
|
+
def write_byte(byte)
|
87
|
+
@protocol.write_byte(byte)
|
88
|
+
end
|
89
|
+
|
90
|
+
def write_i16(i16)
|
91
|
+
@protocol.write_i16(i16)
|
92
|
+
end
|
93
|
+
|
94
|
+
def write_i32(i32)
|
95
|
+
@protocol.write_i32(i32)
|
96
|
+
end
|
97
|
+
|
98
|
+
def write_i64(i64)
|
99
|
+
@protocol.write_i64(i64)
|
100
|
+
end
|
101
|
+
|
102
|
+
def write_double(dub)
|
103
|
+
@protocol.write_double(dub)
|
104
|
+
end
|
105
|
+
|
106
|
+
def write_string(str)
|
107
|
+
@protocol.write_string(str)
|
108
|
+
end
|
109
|
+
|
110
|
+
def write_binary(buf)
|
111
|
+
@protocol.write_binary(buf)
|
112
|
+
end
|
113
|
+
|
114
|
+
def read_message_begin
|
115
|
+
@protocol.read_message_begin
|
116
|
+
end
|
117
|
+
|
118
|
+
def read_message_end
|
119
|
+
@protocol.read_message_end
|
120
|
+
end
|
121
|
+
|
122
|
+
def read_struct_begin
|
123
|
+
@protocol.read_struct_begin
|
124
|
+
end
|
125
|
+
|
126
|
+
def read_struct_end
|
127
|
+
@protocol.read_struct_end
|
128
|
+
end
|
129
|
+
|
130
|
+
def read_field_begin
|
131
|
+
@protocol.read_field_begin
|
132
|
+
end
|
133
|
+
|
134
|
+
def read_field_end
|
135
|
+
@protocol.read_field_end
|
136
|
+
end
|
137
|
+
|
138
|
+
def read_map_begin
|
139
|
+
@protocol.read_map_begin
|
140
|
+
end
|
141
|
+
|
142
|
+
def read_map_end
|
143
|
+
@protocol.read_map_end
|
144
|
+
end
|
145
|
+
|
146
|
+
def read_list_begin
|
147
|
+
@protocol.read_list_begin
|
148
|
+
end
|
149
|
+
|
150
|
+
def read_list_end
|
151
|
+
@protocol.read_list_end
|
152
|
+
end
|
153
|
+
|
154
|
+
def read_set_begin
|
155
|
+
@protocol.read_set_begin
|
156
|
+
end
|
157
|
+
|
158
|
+
def read_set_end
|
159
|
+
@protocol.read_set_end
|
160
|
+
end
|
161
|
+
|
162
|
+
def read_bool
|
163
|
+
@protocol.read_bool
|
164
|
+
end
|
165
|
+
|
166
|
+
def read_byte
|
167
|
+
@protocol.read_byte
|
168
|
+
end
|
169
|
+
|
170
|
+
def read_i16
|
171
|
+
@protocol.read_i16
|
172
|
+
end
|
173
|
+
|
174
|
+
def read_i32
|
175
|
+
@protocol.read_i32
|
176
|
+
end
|
177
|
+
|
178
|
+
def read_i64
|
179
|
+
@protocol.read_i64
|
180
|
+
end
|
181
|
+
|
182
|
+
def read_double
|
183
|
+
@protocol.read_double
|
184
|
+
end
|
185
|
+
|
186
|
+
def read_string
|
187
|
+
@protocol.read_string
|
188
|
+
end
|
189
|
+
|
190
|
+
def read_binary
|
191
|
+
@protocol.read_binary
|
192
|
+
end
|
193
|
+
end
|
194
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
#
|
2
|
+
# Licensed to the Apache Software Foundation (ASF) under one
|
3
|
+
# or more contributor license agreements. See the NOTICE file
|
4
|
+
# distributed with this work for additional information
|
5
|
+
# regarding copyright ownership. The ASF licenses this file
|
6
|
+
# to you under the Apache License, Version 2.0 (the
|
7
|
+
# "License"); you may not use this file except in compliance
|
8
|
+
# with the License. You may obtain a copy of the License at
|
9
|
+
#
|
10
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
11
|
+
#
|
12
|
+
# Unless required by applicable law or agreed to in writing,
|
13
|
+
# software distributed under the License is distributed on an
|
14
|
+
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
15
|
+
# KIND, either express or implied. See the License for the
|
16
|
+
# specific language governing permissions and limitations
|
17
|
+
# under the License.
|
18
|
+
#
|
19
|
+
|
20
|
+
module Thrift
|
21
|
+
class Deserializer
|
22
|
+
def initialize(protocol_factory = BinaryProtocolFactory.new)
|
23
|
+
@transport = MemoryBufferTransport.new
|
24
|
+
@protocol = protocol_factory.get_protocol(@transport)
|
25
|
+
end
|
26
|
+
|
27
|
+
def deserialize(base, buffer)
|
28
|
+
@transport.reset_buffer(buffer)
|
29
|
+
base.read(@protocol)
|
30
|
+
base
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
#
|
2
|
+
# Licensed to the Apache Software Foundation (ASF) under one
|
3
|
+
# or more contributor license agreements. See the NOTICE file
|
4
|
+
# distributed with this work for additional information
|
5
|
+
# regarding copyright ownership. The ASF licenses this file
|
6
|
+
# to you under the Apache License, Version 2.0 (the
|
7
|
+
# "License"); you may not use this file except in compliance
|
8
|
+
# with the License. You may obtain a copy of the License at
|
9
|
+
#
|
10
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
11
|
+
#
|
12
|
+
# Unless required by applicable law or agreed to in writing,
|
13
|
+
# software distributed under the License is distributed on an
|
14
|
+
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
15
|
+
# KIND, either express or implied. See the License for the
|
16
|
+
# specific language governing permissions and limitations
|
17
|
+
# under the License.
|
18
|
+
#
|
19
|
+
|
20
|
+
module Thrift
|
21
|
+
class Serializer
|
22
|
+
def initialize(protocol_factory = BinaryProtocolFactory.new)
|
23
|
+
@transport = MemoryBufferTransport.new
|
24
|
+
@protocol = protocol_factory.get_protocol(@transport)
|
25
|
+
end
|
26
|
+
|
27
|
+
def serialize(base)
|
28
|
+
@transport.reset_buffer
|
29
|
+
base.write(@protocol)
|
30
|
+
@transport.read(@transport.available)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
@@ -0,0 +1,31 @@
|
|
1
|
+
#
|
2
|
+
# Licensed to the Apache Software Foundation (ASF) under one
|
3
|
+
# or more contributor license agreements. See the NOTICE file
|
4
|
+
# distributed with this work for additional information
|
5
|
+
# regarding copyright ownership. The ASF licenses this file
|
6
|
+
# to you under the Apache License, Version 2.0 (the
|
7
|
+
# "License"); you may not use this file except in compliance
|
8
|
+
# with the License. You may obtain a copy of the License at
|
9
|
+
#
|
10
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
11
|
+
#
|
12
|
+
# Unless required by applicable law or agreed to in writing,
|
13
|
+
# software distributed under the License is distributed on an
|
14
|
+
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
15
|
+
# KIND, either express or implied. See the License for the
|
16
|
+
# specific language governing permissions and limitations
|
17
|
+
# under the License.
|
18
|
+
#
|
19
|
+
|
20
|
+
module Thrift
|
21
|
+
class BaseServer
|
22
|
+
def initialize(processor, server_transport, transport_factory=nil, protocol_factory=nil)
|
23
|
+
@processor = processor
|
24
|
+
@server_transport = server_transport
|
25
|
+
@transport_factory = transport_factory ? transport_factory : Thrift::BaseTransportFactory.new
|
26
|
+
@protocol_factory = protocol_factory ? protocol_factory : Thrift::BinaryProtocolFactory.new
|
27
|
+
end
|
28
|
+
|
29
|
+
def serve; nil; end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
#
|
2
|
+
# Licensed to the Apache Software Foundation (ASF) under one
|
3
|
+
# or more contributor license agreements. See the NOTICE file
|
4
|
+
# distributed with this work for additional information
|
5
|
+
# regarding copyright ownership. The ASF licenses this file
|
6
|
+
# to you under the Apache License, Version 2.0 (the
|
7
|
+
# "License"); you may not use this file except in compliance
|
8
|
+
# with the License. You may obtain a copy of the License at
|
9
|
+
#
|
10
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
11
|
+
#
|
12
|
+
# Unless required by applicable law or agreed to in writing,
|
13
|
+
# software distributed under the License is distributed on an
|
14
|
+
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
15
|
+
# KIND, either express or implied. See the License for the
|
16
|
+
# specific language governing permissions and limitations
|
17
|
+
# under the License.
|
18
|
+
#
|
19
|
+
|
20
|
+
require 'mongrel'
|
21
|
+
|
22
|
+
## Sticks a service on a URL, using mongrel to do the HTTP work
|
23
|
+
# <b>DEPRECATED:</b> Please use <tt>Thrift::ThinHTTPServer</tt> instead.
|
24
|
+
module Thrift
|
25
|
+
class MongrelHTTPServer < BaseServer
|
26
|
+
class Handler < Mongrel::HttpHandler
|
27
|
+
def initialize(processor, protocol_factory)
|
28
|
+
@processor = processor
|
29
|
+
@protocol_factory = protocol_factory
|
30
|
+
end
|
31
|
+
|
32
|
+
def process(request, response)
|
33
|
+
if request.params["REQUEST_METHOD"] == "POST"
|
34
|
+
response.start(200) do |head, out|
|
35
|
+
head["Content-Type"] = "application/x-thrift"
|
36
|
+
transport = IOStreamTransport.new request.body, out
|
37
|
+
protocol = @protocol_factory.get_protocol transport
|
38
|
+
@processor.process protocol, protocol
|
39
|
+
end
|
40
|
+
else
|
41
|
+
response.start(404) { }
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def initialize(processor, opts={})
|
47
|
+
Kernel.warn "[DEPRECATION WARNING] `Thrift::MongrelHTTPServer` is deprecated. Please use `Thrift::ThinHTTPServer` instead."
|
48
|
+
port = opts[:port] || 80
|
49
|
+
ip = opts[:ip] || "0.0.0.0"
|
50
|
+
path = opts[:path] || ""
|
51
|
+
protocol_factory = opts[:protocol_factory] || BinaryProtocolFactory.new
|
52
|
+
@server = Mongrel::HttpServer.new ip, port
|
53
|
+
@server.register "/#{path}", Handler.new(processor, protocol_factory)
|
54
|
+
end
|
55
|
+
|
56
|
+
def serve
|
57
|
+
@server.run.join
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,305 @@
|
|
1
|
+
#
|
2
|
+
# Licensed to the Apache Software Foundation (ASF) under one
|
3
|
+
# or more contributor license agreements. See the NOTICE file
|
4
|
+
# distributed with this work for additional information
|
5
|
+
# regarding copyright ownership. The ASF licenses this file
|
6
|
+
# to you under the Apache License, Version 2.0 (the
|
7
|
+
# "License"); you may not use this file except in compliance
|
8
|
+
# with the License. You may obtain a copy of the License at
|
9
|
+
#
|
10
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
11
|
+
#
|
12
|
+
# Unless required by applicable law or agreed to in writing,
|
13
|
+
# software distributed under the License is distributed on an
|
14
|
+
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
15
|
+
# KIND, either express or implied. See the License for the
|
16
|
+
# specific language governing permissions and limitations
|
17
|
+
# under the License.
|
18
|
+
#
|
19
|
+
|
20
|
+
require 'logger'
|
21
|
+
require 'thread'
|
22
|
+
|
23
|
+
module Thrift
|
24
|
+
# this class expects to always use a FramedTransport for reading messages
|
25
|
+
class NonblockingServer < BaseServer
|
26
|
+
def initialize(processor, server_transport, transport_factory=nil, protocol_factory=nil, num=20, logger=nil)
|
27
|
+
super(processor, server_transport, transport_factory, protocol_factory)
|
28
|
+
@num_threads = num
|
29
|
+
if logger.nil?
|
30
|
+
@logger = Logger.new(STDERR)
|
31
|
+
@logger.level = Logger::WARN
|
32
|
+
else
|
33
|
+
@logger = logger
|
34
|
+
end
|
35
|
+
@shutdown_semaphore = Mutex.new
|
36
|
+
@transport_semaphore = Mutex.new
|
37
|
+
end
|
38
|
+
|
39
|
+
def serve
|
40
|
+
@logger.info "Starting #{self}"
|
41
|
+
@server_transport.listen
|
42
|
+
@io_manager = start_io_manager
|
43
|
+
|
44
|
+
begin
|
45
|
+
loop do
|
46
|
+
break if @server_transport.closed?
|
47
|
+
begin
|
48
|
+
rd, = select([@server_transport], nil, nil, 0.1)
|
49
|
+
rescue Errno::EBADF => e
|
50
|
+
# In Ruby 1.9, calling @server_transport.close in shutdown paths causes the select() to raise an
|
51
|
+
# Errno::EBADF. If this happens, ignore it and retry the loop.
|
52
|
+
break
|
53
|
+
end
|
54
|
+
next if rd.nil?
|
55
|
+
socket = @server_transport.accept
|
56
|
+
@logger.debug "Accepted socket: #{socket.inspect}"
|
57
|
+
@io_manager.add_connection socket
|
58
|
+
end
|
59
|
+
rescue IOError => e
|
60
|
+
end
|
61
|
+
# we must be shutting down
|
62
|
+
@logger.info "#{self} is shutting down, goodbye"
|
63
|
+
ensure
|
64
|
+
@transport_semaphore.synchronize do
|
65
|
+
@server_transport.close
|
66
|
+
end
|
67
|
+
@io_manager.ensure_closed unless @io_manager.nil?
|
68
|
+
end
|
69
|
+
|
70
|
+
def shutdown(timeout = 0, block = true)
|
71
|
+
@shutdown_semaphore.synchronize do
|
72
|
+
return if @is_shutdown
|
73
|
+
@is_shutdown = true
|
74
|
+
end
|
75
|
+
# nonblocking is intended for calling from within a Handler
|
76
|
+
# but we can't change the order of operations here, so lets thread
|
77
|
+
shutdown_proc = lambda do
|
78
|
+
@io_manager.shutdown(timeout)
|
79
|
+
@transport_semaphore.synchronize do
|
80
|
+
@server_transport.close # this will break the accept loop
|
81
|
+
end
|
82
|
+
end
|
83
|
+
if block
|
84
|
+
shutdown_proc.call
|
85
|
+
else
|
86
|
+
Thread.new &shutdown_proc
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
private
|
91
|
+
|
92
|
+
def start_io_manager
|
93
|
+
iom = IOManager.new(@processor, @server_transport, @transport_factory, @protocol_factory, @num_threads, @logger)
|
94
|
+
iom.spawn
|
95
|
+
iom
|
96
|
+
end
|
97
|
+
|
98
|
+
class IOManager # :nodoc:
|
99
|
+
DEFAULT_BUFFER = 2**20
|
100
|
+
|
101
|
+
def initialize(processor, server_transport, transport_factory, protocol_factory, num, logger)
|
102
|
+
@processor = processor
|
103
|
+
@server_transport = server_transport
|
104
|
+
@transport_factory = transport_factory
|
105
|
+
@protocol_factory = protocol_factory
|
106
|
+
@num_threads = num
|
107
|
+
@logger = logger
|
108
|
+
@connections = []
|
109
|
+
@buffers = Hash.new { |h,k| h[k] = '' }
|
110
|
+
@signal_queue = Queue.new
|
111
|
+
@signal_pipes = IO.pipe
|
112
|
+
@signal_pipes[1].sync = true
|
113
|
+
@worker_queue = Queue.new
|
114
|
+
@shutdown_queue = Queue.new
|
115
|
+
end
|
116
|
+
|
117
|
+
def add_connection(socket)
|
118
|
+
signal [:connection, socket]
|
119
|
+
end
|
120
|
+
|
121
|
+
def spawn
|
122
|
+
@iom_thread = Thread.new do
|
123
|
+
@logger.debug "Starting #{self}"
|
124
|
+
run
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
def shutdown(timeout = 0)
|
129
|
+
@logger.debug "#{self} is shutting down workers"
|
130
|
+
@worker_queue.clear
|
131
|
+
@num_threads.times { @worker_queue.push [:shutdown] }
|
132
|
+
signal [:shutdown, timeout]
|
133
|
+
@shutdown_queue.pop
|
134
|
+
@signal_pipes[0].close
|
135
|
+
@signal_pipes[1].close
|
136
|
+
@logger.debug "#{self} is shutting down, goodbye"
|
137
|
+
end
|
138
|
+
|
139
|
+
def ensure_closed
|
140
|
+
kill_worker_threads if @worker_threads
|
141
|
+
@iom_thread.kill
|
142
|
+
end
|
143
|
+
|
144
|
+
private
|
145
|
+
|
146
|
+
def run
|
147
|
+
spin_worker_threads
|
148
|
+
|
149
|
+
loop do
|
150
|
+
rd, = select([@signal_pipes[0], *@connections])
|
151
|
+
if rd.delete @signal_pipes[0]
|
152
|
+
break if read_signals == :shutdown
|
153
|
+
end
|
154
|
+
rd.each do |fd|
|
155
|
+
begin
|
156
|
+
if fd.handle.eof?
|
157
|
+
remove_connection fd
|
158
|
+
else
|
159
|
+
read_connection fd
|
160
|
+
end
|
161
|
+
rescue Errno::ECONNRESET
|
162
|
+
remove_connection fd
|
163
|
+
end
|
164
|
+
end
|
165
|
+
end
|
166
|
+
join_worker_threads(@shutdown_timeout)
|
167
|
+
ensure
|
168
|
+
@shutdown_queue.push :shutdown
|
169
|
+
end
|
170
|
+
|
171
|
+
def read_connection(fd)
|
172
|
+
@buffers[fd] << fd.read(DEFAULT_BUFFER)
|
173
|
+
while(frame = slice_frame!(@buffers[fd]))
|
174
|
+
@logger.debug "#{self} is processing a frame"
|
175
|
+
@worker_queue.push [:frame, fd, frame]
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
def spin_worker_threads
|
180
|
+
@logger.debug "#{self} is spinning up worker threads"
|
181
|
+
@worker_threads = []
|
182
|
+
@num_threads.times do
|
183
|
+
@worker_threads << spin_thread
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
def spin_thread
|
188
|
+
Worker.new(@processor, @transport_factory, @protocol_factory, @logger, @worker_queue).spawn
|
189
|
+
end
|
190
|
+
|
191
|
+
def signal(msg)
|
192
|
+
@signal_queue << msg
|
193
|
+
@signal_pipes[1].write " "
|
194
|
+
end
|
195
|
+
|
196
|
+
def read_signals
|
197
|
+
# clear the signal pipe
|
198
|
+
# note that since read_nonblock is broken in jruby,
|
199
|
+
# we can only read up to a set number of signals at once
|
200
|
+
sigstr = @signal_pipes[0].readpartial(1024)
|
201
|
+
# now read the signals
|
202
|
+
begin
|
203
|
+
sigstr.length.times do
|
204
|
+
signal, obj = @signal_queue.pop(true)
|
205
|
+
case signal
|
206
|
+
when :connection
|
207
|
+
@connections << obj
|
208
|
+
when :shutdown
|
209
|
+
@shutdown_timeout = obj
|
210
|
+
return :shutdown
|
211
|
+
end
|
212
|
+
end
|
213
|
+
rescue ThreadError
|
214
|
+
# out of signals
|
215
|
+
# note that in a perfect world this would never happen, since we're
|
216
|
+
# only reading the number of signals pushed on the pipe, but given the lack
|
217
|
+
# of locks, in theory we could clear the pipe/queue while a new signal is being
|
218
|
+
# placed on the pipe, at which point our next read_signals would hit this error
|
219
|
+
end
|
220
|
+
end
|
221
|
+
|
222
|
+
def remove_connection(fd)
|
223
|
+
# don't explicitly close it, a thread may still be writing to it
|
224
|
+
@connections.delete fd
|
225
|
+
@buffers.delete fd
|
226
|
+
end
|
227
|
+
|
228
|
+
def join_worker_threads(shutdown_timeout)
|
229
|
+
start = Time.now
|
230
|
+
@worker_threads.each do |t|
|
231
|
+
if shutdown_timeout > 0
|
232
|
+
timeout = (start + shutdown_timeout) - Time.now
|
233
|
+
break if timeout <= 0
|
234
|
+
t.join(timeout)
|
235
|
+
else
|
236
|
+
t.join
|
237
|
+
end
|
238
|
+
end
|
239
|
+
kill_worker_threads
|
240
|
+
end
|
241
|
+
|
242
|
+
def kill_worker_threads
|
243
|
+
@worker_threads.each do |t|
|
244
|
+
t.kill if t.status
|
245
|
+
end
|
246
|
+
@worker_threads.clear
|
247
|
+
end
|
248
|
+
|
249
|
+
def slice_frame!(buf)
|
250
|
+
if buf.length >= 4
|
251
|
+
size = buf.unpack('N').first
|
252
|
+
if buf.length >= size + 4
|
253
|
+
buf.slice!(0, size + 4)
|
254
|
+
else
|
255
|
+
nil
|
256
|
+
end
|
257
|
+
else
|
258
|
+
nil
|
259
|
+
end
|
260
|
+
end
|
261
|
+
|
262
|
+
class Worker # :nodoc:
|
263
|
+
def initialize(processor, transport_factory, protocol_factory, logger, queue)
|
264
|
+
@processor = processor
|
265
|
+
@transport_factory = transport_factory
|
266
|
+
@protocol_factory = protocol_factory
|
267
|
+
@logger = logger
|
268
|
+
@queue = queue
|
269
|
+
end
|
270
|
+
|
271
|
+
def spawn
|
272
|
+
Thread.new do
|
273
|
+
@logger.debug "#{self} is spawning"
|
274
|
+
run
|
275
|
+
end
|
276
|
+
end
|
277
|
+
|
278
|
+
private
|
279
|
+
|
280
|
+
def run
|
281
|
+
loop do
|
282
|
+
cmd, *args = @queue.pop
|
283
|
+
case cmd
|
284
|
+
when :shutdown
|
285
|
+
@logger.debug "#{self} is shutting down, goodbye"
|
286
|
+
break
|
287
|
+
when :frame
|
288
|
+
fd, frame = args
|
289
|
+
begin
|
290
|
+
otrans = @transport_factory.get_transport(fd)
|
291
|
+
oprot = @protocol_factory.get_protocol(otrans)
|
292
|
+
membuf = MemoryBufferTransport.new(frame)
|
293
|
+
itrans = @transport_factory.get_transport(membuf)
|
294
|
+
iprot = @protocol_factory.get_protocol(itrans)
|
295
|
+
@processor.process(iprot, oprot)
|
296
|
+
rescue => e
|
297
|
+
@logger.error "#{Thread.current.inspect} raised error: #{e.inspect}\n#{e.backtrace.join("\n")}"
|
298
|
+
end
|
299
|
+
end
|
300
|
+
end
|
301
|
+
end
|
302
|
+
end
|
303
|
+
end
|
304
|
+
end
|
305
|
+
end
|