thrift 0.2.0 → 0.2.0.2
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.
- data.tar.gz.sig +0 -0
- data/CHANGELOG +1 -0
- data/Manifest +14 -2
- data/benchmark/gen-rb/BenchmarkService.rb +81 -0
- data/benchmark/gen-rb/Benchmark_constants.rb +11 -0
- data/benchmark/gen-rb/Benchmark_types.rb +10 -0
- data/ext/extconf.rb +1 -1
- data/lib/thrift/protocol/binaryprotocol.rb +213 -0
- data/lib/thrift/protocol/binaryprotocolaccelerated.rb +19 -0
- data/lib/thrift/protocol/tbinaryprotocol.rb +2 -0
- data/lib/thrift/protocol/tprotocol.rb +2 -0
- data/lib/thrift/server/httpserver.rb +44 -0
- data/lib/thrift/server/nonblockingserver.rb +278 -0
- data/lib/thrift/server/thttpserver.rb +2 -0
- data/lib/thrift/server/tserver.rb +2 -0
- data/spec/gen-rb/NonblockingService.rb +268 -0
- data/spec/gen-rb/ThriftSpec_constants.rb +11 -0
- data/spec/gen-rb/ThriftSpec_types.rb +134 -0
- data/thrift.gemspec +5 -5
- metadata +36 -9
- metadata.gz.sig +0 -0
- data/ext/conftest.dSYM/Contents/Info.plist +0 -25
- data/ext/conftest.dSYM/Contents/Resources/DWARF/conftest +0 -0
@@ -0,0 +1,278 @@
|
|
1
|
+
require 'thrift/server'
|
2
|
+
require 'logger'
|
3
|
+
require 'thread'
|
4
|
+
|
5
|
+
module Thrift
|
6
|
+
# this class expects to always use a FramedTransport for reading messages
|
7
|
+
class NonblockingServer < Server
|
8
|
+
def initialize(processor, serverTransport, transportFactory=nil, protocolFactory=nil, num=20, logger = nil)
|
9
|
+
super(processor, serverTransport, transportFactory, protocolFactory)
|
10
|
+
@num_threads = num
|
11
|
+
if logger.nil?
|
12
|
+
@logger = Logger.new(STDERR)
|
13
|
+
@logger.level = Logger::WARN
|
14
|
+
else
|
15
|
+
@logger = logger
|
16
|
+
end
|
17
|
+
@shutdown_semaphore = Mutex.new
|
18
|
+
@transport_semaphore = Mutex.new
|
19
|
+
end
|
20
|
+
|
21
|
+
def serve
|
22
|
+
@logger.info "Starting #{self}"
|
23
|
+
@serverTransport.listen
|
24
|
+
@io_manager = start_io_manager
|
25
|
+
|
26
|
+
begin
|
27
|
+
loop do
|
28
|
+
break if @serverTransport.closed?
|
29
|
+
rd, = select([@serverTransport], nil, nil, 0.1)
|
30
|
+
next if rd.nil?
|
31
|
+
socket = @serverTransport.accept
|
32
|
+
@logger.debug "Accepted socket: #{socket.inspect}"
|
33
|
+
@io_manager.add_connection socket
|
34
|
+
end
|
35
|
+
rescue IOError => e
|
36
|
+
end
|
37
|
+
# we must be shutting down
|
38
|
+
@logger.info "#{self} is shutting down, goodbye"
|
39
|
+
ensure
|
40
|
+
@transport_semaphore.synchronize do
|
41
|
+
@serverTransport.close
|
42
|
+
end
|
43
|
+
@io_manager.ensure_closed unless @io_manager.nil?
|
44
|
+
end
|
45
|
+
|
46
|
+
def shutdown(timeout = 0, block = true)
|
47
|
+
@shutdown_semaphore.synchronize do
|
48
|
+
return if @is_shutdown
|
49
|
+
@is_shutdown = true
|
50
|
+
end
|
51
|
+
# nonblocking is intended for calling from within a Handler
|
52
|
+
# but we can't change the order of operations here, so lets thread
|
53
|
+
shutdown_proc = lambda do
|
54
|
+
@io_manager.shutdown(timeout)
|
55
|
+
@transport_semaphore.synchronize do
|
56
|
+
@serverTransport.close # this will break the accept loop
|
57
|
+
end
|
58
|
+
end
|
59
|
+
if block
|
60
|
+
shutdown_proc.call
|
61
|
+
else
|
62
|
+
Thread.new &shutdown_proc
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
private
|
67
|
+
|
68
|
+
def start_io_manager
|
69
|
+
iom = IOManager.new(@processor, @serverTransport, @transportFactory, @protocolFactory, @num_threads, @logger)
|
70
|
+
iom.spawn
|
71
|
+
iom
|
72
|
+
end
|
73
|
+
|
74
|
+
class IOManager # :nodoc:
|
75
|
+
DEFAULT_BUFFER = 2**20
|
76
|
+
|
77
|
+
def initialize(processor, serverTransport, transportFactory, protocolFactory, num, logger)
|
78
|
+
@processor = processor
|
79
|
+
@serverTransport = serverTransport
|
80
|
+
@transportFactory = transportFactory
|
81
|
+
@protocolFactory = protocolFactory
|
82
|
+
@num_threads = num
|
83
|
+
@logger = logger
|
84
|
+
@connections = []
|
85
|
+
@buffers = Hash.new { |h,k| h[k] = '' }
|
86
|
+
@signal_queue = Queue.new
|
87
|
+
@signal_pipes = IO.pipe
|
88
|
+
@signal_pipes[1].sync = true
|
89
|
+
@worker_queue = Queue.new
|
90
|
+
@shutdown_queue = Queue.new
|
91
|
+
end
|
92
|
+
|
93
|
+
def add_connection(socket)
|
94
|
+
signal [:connection, socket]
|
95
|
+
end
|
96
|
+
|
97
|
+
def spawn
|
98
|
+
@iom_thread = Thread.new do
|
99
|
+
@logger.debug "Starting #{self}"
|
100
|
+
run
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
def shutdown(timeout = 0)
|
105
|
+
@logger.debug "#{self} is shutting down workers"
|
106
|
+
@worker_queue.clear
|
107
|
+
@num_threads.times { @worker_queue.push [:shutdown] }
|
108
|
+
signal [:shutdown, timeout]
|
109
|
+
@shutdown_queue.pop
|
110
|
+
@signal_pipes[0].close
|
111
|
+
@signal_pipes[1].close
|
112
|
+
@logger.debug "#{self} is shutting down, goodbye"
|
113
|
+
end
|
114
|
+
|
115
|
+
def ensure_closed
|
116
|
+
kill_worker_threads if @worker_threads
|
117
|
+
@iom_thread.kill
|
118
|
+
end
|
119
|
+
|
120
|
+
private
|
121
|
+
|
122
|
+
def run
|
123
|
+
spin_worker_threads
|
124
|
+
|
125
|
+
loop do
|
126
|
+
rd, = select([@signal_pipes[0], *@connections])
|
127
|
+
if rd.delete @signal_pipes[0]
|
128
|
+
break if read_signals == :shutdown
|
129
|
+
end
|
130
|
+
rd.each do |fd|
|
131
|
+
if fd.handle.eof?
|
132
|
+
remove_connection fd
|
133
|
+
else
|
134
|
+
read_connection fd
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
138
|
+
join_worker_threads(@shutdown_timeout)
|
139
|
+
ensure
|
140
|
+
@shutdown_queue.push :shutdown
|
141
|
+
end
|
142
|
+
|
143
|
+
def read_connection(fd)
|
144
|
+
@buffers[fd] << fd.read(DEFAULT_BUFFER)
|
145
|
+
frame = slice_frame!(@buffers[fd])
|
146
|
+
if frame
|
147
|
+
@logger.debug "#{self} is processing a frame"
|
148
|
+
@worker_queue.push [:frame, fd, frame]
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
def spin_worker_threads
|
153
|
+
@logger.debug "#{self} is spinning up worker threads"
|
154
|
+
@worker_threads = []
|
155
|
+
@num_threads.times do
|
156
|
+
@worker_threads << spin_thread
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
def spin_thread
|
161
|
+
Worker.new(@processor, @transportFactory, @protocolFactory, @logger, @worker_queue).spawn
|
162
|
+
end
|
163
|
+
|
164
|
+
def signal(msg)
|
165
|
+
@signal_queue << msg
|
166
|
+
@signal_pipes[1].write " "
|
167
|
+
end
|
168
|
+
|
169
|
+
def read_signals
|
170
|
+
# clear the signal pipe
|
171
|
+
# note that since read_nonblock is broken in jruby,
|
172
|
+
# we can only read up to a set number of signals at once
|
173
|
+
sigstr = @signal_pipes[0].readpartial(1024)
|
174
|
+
# now read the signals
|
175
|
+
begin
|
176
|
+
sigstr.length.times do
|
177
|
+
signal, obj = @signal_queue.pop(true)
|
178
|
+
case signal
|
179
|
+
when :connection
|
180
|
+
@connections << obj
|
181
|
+
when :shutdown
|
182
|
+
@shutdown_timeout = obj
|
183
|
+
return :shutdown
|
184
|
+
end
|
185
|
+
end
|
186
|
+
rescue ThreadError
|
187
|
+
# out of signals
|
188
|
+
# note that in a perfect world this would never happen, since we're
|
189
|
+
# only reading the number of signals pushed on the pipe, but given the lack
|
190
|
+
# of locks, in theory we could clear the pipe/queue while a new signal is being
|
191
|
+
# placed on the pipe, at which point our next read_signals would hit this error
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
def remove_connection(fd)
|
196
|
+
# don't explicitly close it, a thread may still be writing to it
|
197
|
+
@connections.delete fd
|
198
|
+
@buffers.delete fd
|
199
|
+
end
|
200
|
+
|
201
|
+
def join_worker_threads(shutdown_timeout)
|
202
|
+
start = Time.now
|
203
|
+
@worker_threads.each do |t|
|
204
|
+
if shutdown_timeout > 0
|
205
|
+
timeout = (start + shutdown_timeout) - Time.now
|
206
|
+
break if timeout <= 0
|
207
|
+
t.join(timeout)
|
208
|
+
else
|
209
|
+
t.join
|
210
|
+
end
|
211
|
+
end
|
212
|
+
kill_worker_threads
|
213
|
+
end
|
214
|
+
|
215
|
+
def kill_worker_threads
|
216
|
+
@worker_threads.each do |t|
|
217
|
+
t.kill if t.status
|
218
|
+
end
|
219
|
+
@worker_threads.clear
|
220
|
+
end
|
221
|
+
|
222
|
+
def slice_frame!(buf)
|
223
|
+
if buf.length >= 4
|
224
|
+
size = buf.unpack('N').first
|
225
|
+
if buf.length >= size + 4
|
226
|
+
buf.slice!(0, size + 4)
|
227
|
+
else
|
228
|
+
nil
|
229
|
+
end
|
230
|
+
else
|
231
|
+
nil
|
232
|
+
end
|
233
|
+
end
|
234
|
+
|
235
|
+
class Worker # :nodoc:
|
236
|
+
def initialize(processor, transportFactory, protocolFactory, logger, queue)
|
237
|
+
@processor = processor
|
238
|
+
@transportFactory = transportFactory
|
239
|
+
@protocolFactory = protocolFactory
|
240
|
+
@logger = logger
|
241
|
+
@queue = queue
|
242
|
+
end
|
243
|
+
|
244
|
+
def spawn
|
245
|
+
Thread.new do
|
246
|
+
@logger.debug "#{self} is spawning"
|
247
|
+
run
|
248
|
+
end
|
249
|
+
end
|
250
|
+
|
251
|
+
private
|
252
|
+
|
253
|
+
def run
|
254
|
+
loop do
|
255
|
+
cmd, *args = @queue.pop
|
256
|
+
case cmd
|
257
|
+
when :shutdown
|
258
|
+
@logger.debug "#{self} is shutting down, goodbye"
|
259
|
+
break
|
260
|
+
when :frame
|
261
|
+
fd, frame = args
|
262
|
+
begin
|
263
|
+
otrans = @transportFactory.get_transport(fd)
|
264
|
+
oprot = @protocolFactory.get_protocol(otrans)
|
265
|
+
membuf = MemoryBuffer.new(frame)
|
266
|
+
itrans = @transportFactory.get_transport(membuf)
|
267
|
+
iprot = @protocolFactory.get_protocol(itrans)
|
268
|
+
@processor.process(iprot, oprot)
|
269
|
+
rescue => e
|
270
|
+
@logger.error "#{Thread.current.inspect} raised error: #{e.inspect}\n#{e.backtrace.join("\n")}"
|
271
|
+
end
|
272
|
+
end
|
273
|
+
end
|
274
|
+
end
|
275
|
+
end
|
276
|
+
end
|
277
|
+
end
|
278
|
+
end
|
@@ -0,0 +1,268 @@
|
|
1
|
+
#
|
2
|
+
# Autogenerated by Thrift
|
3
|
+
#
|
4
|
+
# DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING
|
5
|
+
#
|
6
|
+
|
7
|
+
require 'thrift'
|
8
|
+
require 'thrift/protocol'
|
9
|
+
require File.dirname(__FILE__) + '/ThriftSpec_types'
|
10
|
+
|
11
|
+
module SpecNamespace
|
12
|
+
module NonblockingService
|
13
|
+
class Client
|
14
|
+
include ::Thrift::Client
|
15
|
+
|
16
|
+
def greeting(english)
|
17
|
+
send_greeting(english)
|
18
|
+
return recv_greeting()
|
19
|
+
end
|
20
|
+
|
21
|
+
def send_greeting(english)
|
22
|
+
send_message('greeting', Greeting_args, :english => english)
|
23
|
+
end
|
24
|
+
|
25
|
+
def recv_greeting()
|
26
|
+
result = receive_message(Greeting_result)
|
27
|
+
return result.success unless result.success.nil?
|
28
|
+
raise Thrift::ApplicationException.new(Thrift::ApplicationException::MISSING_RESULT, 'greeting failed: unknown result')
|
29
|
+
end
|
30
|
+
|
31
|
+
def block()
|
32
|
+
send_block()
|
33
|
+
return recv_block()
|
34
|
+
end
|
35
|
+
|
36
|
+
def send_block()
|
37
|
+
send_message('block', Block_args)
|
38
|
+
end
|
39
|
+
|
40
|
+
def recv_block()
|
41
|
+
result = receive_message(Block_result)
|
42
|
+
return result.success unless result.success.nil?
|
43
|
+
raise Thrift::ApplicationException.new(Thrift::ApplicationException::MISSING_RESULT, 'block failed: unknown result')
|
44
|
+
end
|
45
|
+
|
46
|
+
def unblock(n)
|
47
|
+
send_unblock(n)
|
48
|
+
end
|
49
|
+
|
50
|
+
def send_unblock(n)
|
51
|
+
send_message('unblock', Unblock_args, :n => n)
|
52
|
+
end
|
53
|
+
def shutdown()
|
54
|
+
send_shutdown()
|
55
|
+
end
|
56
|
+
|
57
|
+
def send_shutdown()
|
58
|
+
send_message('shutdown', Shutdown_args)
|
59
|
+
end
|
60
|
+
def sleep(seconds)
|
61
|
+
send_sleep(seconds)
|
62
|
+
recv_sleep()
|
63
|
+
end
|
64
|
+
|
65
|
+
def send_sleep(seconds)
|
66
|
+
send_message('sleep', Sleep_args, :seconds => seconds)
|
67
|
+
end
|
68
|
+
|
69
|
+
def recv_sleep()
|
70
|
+
result = receive_message(Sleep_result)
|
71
|
+
return
|
72
|
+
end
|
73
|
+
|
74
|
+
end
|
75
|
+
|
76
|
+
class Processor
|
77
|
+
include ::Thrift::Processor
|
78
|
+
|
79
|
+
def process_greeting(seqid, iprot, oprot)
|
80
|
+
args = read_args(iprot, Greeting_args)
|
81
|
+
result = Greeting_result.new()
|
82
|
+
result.success = @handler.greeting(args.english)
|
83
|
+
write_result(result, oprot, 'greeting', seqid)
|
84
|
+
end
|
85
|
+
|
86
|
+
def process_block(seqid, iprot, oprot)
|
87
|
+
args = read_args(iprot, Block_args)
|
88
|
+
result = Block_result.new()
|
89
|
+
result.success = @handler.block()
|
90
|
+
write_result(result, oprot, 'block', seqid)
|
91
|
+
end
|
92
|
+
|
93
|
+
def process_unblock(seqid, iprot, oprot)
|
94
|
+
args = read_args(iprot, Unblock_args)
|
95
|
+
@handler.unblock(args.n)
|
96
|
+
return
|
97
|
+
end
|
98
|
+
|
99
|
+
def process_shutdown(seqid, iprot, oprot)
|
100
|
+
args = read_args(iprot, Shutdown_args)
|
101
|
+
@handler.shutdown()
|
102
|
+
return
|
103
|
+
end
|
104
|
+
|
105
|
+
def process_sleep(seqid, iprot, oprot)
|
106
|
+
args = read_args(iprot, Sleep_args)
|
107
|
+
result = Sleep_result.new()
|
108
|
+
@handler.sleep(args.seconds)
|
109
|
+
write_result(result, oprot, 'sleep', seqid)
|
110
|
+
end
|
111
|
+
|
112
|
+
end
|
113
|
+
|
114
|
+
# HELPER FUNCTIONS AND STRUCTURES
|
115
|
+
|
116
|
+
class Greeting_args
|
117
|
+
include ::Thrift::Struct
|
118
|
+
ENGLISH = 1
|
119
|
+
|
120
|
+
Thrift::Struct.field_accessor self, :english
|
121
|
+
FIELDS = {
|
122
|
+
ENGLISH => {:type => Thrift::Types::BOOL, :name => 'english'}
|
123
|
+
}
|
124
|
+
|
125
|
+
def struct_fields; FIELDS; end
|
126
|
+
|
127
|
+
def validate
|
128
|
+
end
|
129
|
+
|
130
|
+
end
|
131
|
+
|
132
|
+
class Greeting_result
|
133
|
+
include ::Thrift::Struct
|
134
|
+
SUCCESS = 0
|
135
|
+
|
136
|
+
Thrift::Struct.field_accessor self, :success
|
137
|
+
FIELDS = {
|
138
|
+
SUCCESS => {:type => Thrift::Types::STRUCT, :name => 'success', :class => SpecNamespace::Hello}
|
139
|
+
}
|
140
|
+
|
141
|
+
def struct_fields; FIELDS; end
|
142
|
+
|
143
|
+
def validate
|
144
|
+
end
|
145
|
+
|
146
|
+
end
|
147
|
+
|
148
|
+
class Block_args
|
149
|
+
include ::Thrift::Struct
|
150
|
+
|
151
|
+
FIELDS = {
|
152
|
+
|
153
|
+
}
|
154
|
+
|
155
|
+
def struct_fields; FIELDS; end
|
156
|
+
|
157
|
+
def validate
|
158
|
+
end
|
159
|
+
|
160
|
+
end
|
161
|
+
|
162
|
+
class Block_result
|
163
|
+
include ::Thrift::Struct
|
164
|
+
SUCCESS = 0
|
165
|
+
|
166
|
+
Thrift::Struct.field_accessor self, :success
|
167
|
+
FIELDS = {
|
168
|
+
SUCCESS => {:type => Thrift::Types::BOOL, :name => 'success'}
|
169
|
+
}
|
170
|
+
|
171
|
+
def struct_fields; FIELDS; end
|
172
|
+
|
173
|
+
def validate
|
174
|
+
end
|
175
|
+
|
176
|
+
end
|
177
|
+
|
178
|
+
class Unblock_args
|
179
|
+
include ::Thrift::Struct
|
180
|
+
N = 1
|
181
|
+
|
182
|
+
Thrift::Struct.field_accessor self, :n
|
183
|
+
FIELDS = {
|
184
|
+
N => {:type => Thrift::Types::I32, :name => 'n'}
|
185
|
+
}
|
186
|
+
|
187
|
+
def struct_fields; FIELDS; end
|
188
|
+
|
189
|
+
def validate
|
190
|
+
end
|
191
|
+
|
192
|
+
end
|
193
|
+
|
194
|
+
class Unblock_result
|
195
|
+
include ::Thrift::Struct
|
196
|
+
|
197
|
+
FIELDS = {
|
198
|
+
|
199
|
+
}
|
200
|
+
|
201
|
+
def struct_fields; FIELDS; end
|
202
|
+
|
203
|
+
def validate
|
204
|
+
end
|
205
|
+
|
206
|
+
end
|
207
|
+
|
208
|
+
class Shutdown_args
|
209
|
+
include ::Thrift::Struct
|
210
|
+
|
211
|
+
FIELDS = {
|
212
|
+
|
213
|
+
}
|
214
|
+
|
215
|
+
def struct_fields; FIELDS; end
|
216
|
+
|
217
|
+
def validate
|
218
|
+
end
|
219
|
+
|
220
|
+
end
|
221
|
+
|
222
|
+
class Shutdown_result
|
223
|
+
include ::Thrift::Struct
|
224
|
+
|
225
|
+
FIELDS = {
|
226
|
+
|
227
|
+
}
|
228
|
+
|
229
|
+
def struct_fields; FIELDS; end
|
230
|
+
|
231
|
+
def validate
|
232
|
+
end
|
233
|
+
|
234
|
+
end
|
235
|
+
|
236
|
+
class Sleep_args
|
237
|
+
include ::Thrift::Struct
|
238
|
+
SECONDS = 1
|
239
|
+
|
240
|
+
Thrift::Struct.field_accessor self, :seconds
|
241
|
+
FIELDS = {
|
242
|
+
SECONDS => {:type => Thrift::Types::DOUBLE, :name => 'seconds'}
|
243
|
+
}
|
244
|
+
|
245
|
+
def struct_fields; FIELDS; end
|
246
|
+
|
247
|
+
def validate
|
248
|
+
end
|
249
|
+
|
250
|
+
end
|
251
|
+
|
252
|
+
class Sleep_result
|
253
|
+
include ::Thrift::Struct
|
254
|
+
|
255
|
+
FIELDS = {
|
256
|
+
|
257
|
+
}
|
258
|
+
|
259
|
+
def struct_fields; FIELDS; end
|
260
|
+
|
261
|
+
def validate
|
262
|
+
end
|
263
|
+
|
264
|
+
end
|
265
|
+
|
266
|
+
end
|
267
|
+
|
268
|
+
end
|