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.
Files changed (128) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +43 -0
  3. data/benchmark/Benchmark.thrift +24 -0
  4. data/benchmark/benchmark.rb +271 -0
  5. data/benchmark/client.rb +74 -0
  6. data/benchmark/gen-rb/benchmark_constants.rb +11 -0
  7. data/benchmark/gen-rb/benchmark_service.rb +80 -0
  8. data/benchmark/gen-rb/benchmark_types.rb +10 -0
  9. data/benchmark/server.rb +82 -0
  10. data/benchmark/thin_server.rb +44 -0
  11. data/ext/binary_protocol_accelerated.c +460 -0
  12. data/ext/binary_protocol_accelerated.h +20 -0
  13. data/ext/bytes.c +36 -0
  14. data/ext/bytes.h +31 -0
  15. data/ext/compact_protocol.c +637 -0
  16. data/ext/compact_protocol.h +20 -0
  17. data/ext/constants.h +99 -0
  18. data/ext/extconf.rb +34 -0
  19. data/ext/macros.h +41 -0
  20. data/ext/memory_buffer.c +134 -0
  21. data/ext/memory_buffer.h +20 -0
  22. data/ext/protocol.c +0 -0
  23. data/ext/protocol.h +0 -0
  24. data/ext/strlcpy.c +41 -0
  25. data/ext/strlcpy.h +34 -0
  26. data/ext/struct.c +707 -0
  27. data/ext/struct.h +25 -0
  28. data/ext/thrift_native.c +201 -0
  29. data/lib/thrift.rb +68 -0
  30. data/lib/thrift/bytes.rb +131 -0
  31. data/lib/thrift/client.rb +71 -0
  32. data/lib/thrift/core_ext.rb +23 -0
  33. data/lib/thrift/core_ext/fixnum.rb +29 -0
  34. data/lib/thrift/exceptions.rb +87 -0
  35. data/lib/thrift/multiplexed_processor.rb +76 -0
  36. data/lib/thrift/processor.rb +57 -0
  37. data/lib/thrift/protocol/base_protocol.rb +379 -0
  38. data/lib/thrift/protocol/binary_protocol.rb +237 -0
  39. data/lib/thrift/protocol/binary_protocol_accelerated.rb +39 -0
  40. data/lib/thrift/protocol/compact_protocol.rb +435 -0
  41. data/lib/thrift/protocol/json_protocol.rb +769 -0
  42. data/lib/thrift/protocol/multiplexed_protocol.rb +40 -0
  43. data/lib/thrift/protocol/protocol_decorator.rb +194 -0
  44. data/lib/thrift/serializer/deserializer.rb +33 -0
  45. data/lib/thrift/serializer/serializer.rb +34 -0
  46. data/lib/thrift/server/base_server.rb +31 -0
  47. data/lib/thrift/server/mongrel_http_server.rb +60 -0
  48. data/lib/thrift/server/nonblocking_server.rb +305 -0
  49. data/lib/thrift/server/rack_application.rb +61 -0
  50. data/lib/thrift/server/simple_server.rb +43 -0
  51. data/lib/thrift/server/thin_http_server.rb +51 -0
  52. data/lib/thrift/server/thread_pool_server.rb +75 -0
  53. data/lib/thrift/server/threaded_server.rb +47 -0
  54. data/lib/thrift/struct.rb +237 -0
  55. data/lib/thrift/struct_union.rb +192 -0
  56. data/lib/thrift/thrift_native.rb +24 -0
  57. data/lib/thrift/transport/base_server_transport.rb +37 -0
  58. data/lib/thrift/transport/base_transport.rb +109 -0
  59. data/lib/thrift/transport/buffered_transport.rb +114 -0
  60. data/lib/thrift/transport/framed_transport.rb +117 -0
  61. data/lib/thrift/transport/http_client_transport.rb +56 -0
  62. data/lib/thrift/transport/io_stream_transport.rb +39 -0
  63. data/lib/thrift/transport/memory_buffer_transport.rb +125 -0
  64. data/lib/thrift/transport/server_socket.rb +63 -0
  65. data/lib/thrift/transport/socket.rb +139 -0
  66. data/lib/thrift/transport/unix_server_socket.rb +60 -0
  67. data/lib/thrift/transport/unix_socket.rb +40 -0
  68. data/lib/thrift/types.rb +101 -0
  69. data/lib/thrift/union.rb +179 -0
  70. data/spec/BaseService.thrift +27 -0
  71. data/spec/ExtendedService.thrift +25 -0
  72. data/spec/Referenced.thrift +44 -0
  73. data/spec/ThriftNamespacedSpec.thrift +53 -0
  74. data/spec/ThriftSpec.thrift +183 -0
  75. data/spec/base_protocol_spec.rb +217 -0
  76. data/spec/base_transport_spec.rb +350 -0
  77. data/spec/binary_protocol_accelerated_spec.rb +42 -0
  78. data/spec/binary_protocol_spec.rb +66 -0
  79. data/spec/binary_protocol_spec_shared.rb +455 -0
  80. data/spec/bytes_spec.rb +160 -0
  81. data/spec/client_spec.rb +99 -0
  82. data/spec/compact_protocol_spec.rb +143 -0
  83. data/spec/exception_spec.rb +141 -0
  84. data/spec/flat_spec.rb +62 -0
  85. data/spec/gen-rb/base/base_service.rb +80 -0
  86. data/spec/gen-rb/base/base_service_constants.rb +11 -0
  87. data/spec/gen-rb/base/base_service_types.rb +26 -0
  88. data/spec/gen-rb/extended/extended_service.rb +78 -0
  89. data/spec/gen-rb/extended/extended_service_constants.rb +11 -0
  90. data/spec/gen-rb/extended/extended_service_types.rb +12 -0
  91. data/spec/gen-rb/flat/namespaced_nonblocking_service.rb +272 -0
  92. data/spec/gen-rb/flat/referenced_constants.rb +11 -0
  93. data/spec/gen-rb/flat/referenced_types.rb +17 -0
  94. data/spec/gen-rb/flat/thrift_namespaced_spec_constants.rb +11 -0
  95. data/spec/gen-rb/flat/thrift_namespaced_spec_types.rb +28 -0
  96. data/spec/gen-rb/namespaced_spec_namespace/namespaced_nonblocking_service.rb +272 -0
  97. data/spec/gen-rb/namespaced_spec_namespace/thrift_namespaced_spec_constants.rb +11 -0
  98. data/spec/gen-rb/namespaced_spec_namespace/thrift_namespaced_spec_types.rb +28 -0
  99. data/spec/gen-rb/nonblocking_service.rb +272 -0
  100. data/spec/gen-rb/other_namespace/referenced_constants.rb +11 -0
  101. data/spec/gen-rb/other_namespace/referenced_types.rb +17 -0
  102. data/spec/gen-rb/thrift_spec_constants.rb +11 -0
  103. data/spec/gen-rb/thrift_spec_types.rb +538 -0
  104. data/spec/http_client_spec.rb +120 -0
  105. data/spec/json_protocol_spec.rb +513 -0
  106. data/spec/namespaced_spec.rb +67 -0
  107. data/spec/nonblocking_server_spec.rb +263 -0
  108. data/spec/processor_spec.rb +80 -0
  109. data/spec/serializer_spec.rb +67 -0
  110. data/spec/server_socket_spec.rb +79 -0
  111. data/spec/server_spec.rb +147 -0
  112. data/spec/socket_spec.rb +61 -0
  113. data/spec/socket_spec_shared.rb +104 -0
  114. data/spec/spec_helper.rb +64 -0
  115. data/spec/struct_nested_containers_spec.rb +191 -0
  116. data/spec/struct_spec.rb +293 -0
  117. data/spec/thin_http_server_spec.rb +141 -0
  118. data/spec/types_spec.rb +115 -0
  119. data/spec/union_spec.rb +203 -0
  120. data/spec/unix_socket_spec.rb +107 -0
  121. data/test/debug_proto/gen-rb/debug_proto_test_constants.rb +274 -0
  122. data/test/debug_proto/gen-rb/debug_proto_test_types.rb +761 -0
  123. data/test/debug_proto/gen-rb/empty_service.rb +24 -0
  124. data/test/debug_proto/gen-rb/inherited.rb +79 -0
  125. data/test/debug_proto/gen-rb/reverse_order_service.rb +82 -0
  126. data/test/debug_proto/gen-rb/service_for_exception_with_a_map.rb +81 -0
  127. data/test/debug_proto/gen-rb/srv.rb +330 -0
  128. 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