fl-thrift 0.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 (83) hide show
  1. data/CHANGELOG +4 -0
  2. data/Manifest +81 -0
  3. data/README +43 -0
  4. data/Rakefile +102 -0
  5. data/benchmark/Benchmark.thrift +24 -0
  6. data/benchmark/benchmark.rb +271 -0
  7. data/benchmark/client.rb +74 -0
  8. data/benchmark/server.rb +82 -0
  9. data/benchmark/thin_server.rb +44 -0
  10. data/ext/binary_protocol_accelerated.c +474 -0
  11. data/ext/binary_protocol_accelerated.h +20 -0
  12. data/ext/compact_protocol.c +665 -0
  13. data/ext/compact_protocol.h +20 -0
  14. data/ext/constants.h +95 -0
  15. data/ext/extconf.rb +26 -0
  16. data/ext/macros.h +41 -0
  17. data/ext/memory_buffer.c +76 -0
  18. data/ext/memory_buffer.h +20 -0
  19. data/ext/protocol.c +185 -0
  20. data/ext/protocol.h +20 -0
  21. data/ext/struct.c +606 -0
  22. data/ext/struct.h +67 -0
  23. data/ext/thrift_native.c +194 -0
  24. data/lib/thrift.rb +59 -0
  25. data/lib/thrift/client.rb +62 -0
  26. data/lib/thrift/core_ext.rb +23 -0
  27. data/lib/thrift/core_ext/fixnum.rb +29 -0
  28. data/lib/thrift/exceptions.rb +82 -0
  29. data/lib/thrift/processor.rb +57 -0
  30. data/lib/thrift/protocol/base_protocol.rb +290 -0
  31. data/lib/thrift/protocol/binary_protocol.rb +225 -0
  32. data/lib/thrift/protocol/binary_protocol_accelerated.rb +35 -0
  33. data/lib/thrift/protocol/compact_protocol.rb +422 -0
  34. data/lib/thrift/serializer/deserializer.rb +33 -0
  35. data/lib/thrift/serializer/serializer.rb +34 -0
  36. data/lib/thrift/server/base_server.rb +31 -0
  37. data/lib/thrift/server/mongrel_http_server.rb +58 -0
  38. data/lib/thrift/server/nonblocking_server.rb +296 -0
  39. data/lib/thrift/server/simple_server.rb +43 -0
  40. data/lib/thrift/server/thread_pool_server.rb +75 -0
  41. data/lib/thrift/server/threaded_server.rb +47 -0
  42. data/lib/thrift/struct.rb +298 -0
  43. data/lib/thrift/thrift_native.rb +24 -0
  44. data/lib/thrift/transport/base_server_transport.rb +37 -0
  45. data/lib/thrift/transport/base_transport.rb +70 -0
  46. data/lib/thrift/transport/buffered_transport.rb +77 -0
  47. data/lib/thrift/transport/framed_transport.rb +90 -0
  48. data/lib/thrift/transport/http_client_transport.rb +45 -0
  49. data/lib/thrift/transport/io_stream_transport.rb +39 -0
  50. data/lib/thrift/transport/memory_buffer_transport.rb +96 -0
  51. data/lib/thrift/transport/server_socket.rb +63 -0
  52. data/lib/thrift/transport/socket.rb +136 -0
  53. data/lib/thrift/transport/unix_server_socket.rb +60 -0
  54. data/lib/thrift/transport/unix_socket.rb +40 -0
  55. data/lib/thrift/types.rb +101 -0
  56. data/script/proto_benchmark.rb +121 -0
  57. data/script/read_struct.rb +43 -0
  58. data/script/write_struct.rb +30 -0
  59. data/setup.rb +1585 -0
  60. data/spec/ThriftSpec.thrift +84 -0
  61. data/spec/base_protocol_spec.rb +160 -0
  62. data/spec/base_transport_spec.rb +351 -0
  63. data/spec/binary_protocol_accelerated_spec.rb +41 -0
  64. data/spec/binary_protocol_spec.rb +63 -0
  65. data/spec/binary_protocol_spec_shared.rb +375 -0
  66. data/spec/client_spec.rb +100 -0
  67. data/spec/compact_protocol_spec.rb +117 -0
  68. data/spec/exception_spec.rb +142 -0
  69. data/spec/http_client_spec.rb +49 -0
  70. data/spec/mongrel_http_server_spec.rb +117 -0
  71. data/spec/nonblocking_server_spec.rb +265 -0
  72. data/spec/processor_spec.rb +83 -0
  73. data/spec/serializer_spec.rb +69 -0
  74. data/spec/server_socket_spec.rb +80 -0
  75. data/spec/server_spec.rb +160 -0
  76. data/spec/socket_spec.rb +61 -0
  77. data/spec/socket_spec_shared.rb +104 -0
  78. data/spec/spec_helper.rb +60 -0
  79. data/spec/struct_spec.rb +252 -0
  80. data/spec/types_spec.rb +116 -0
  81. data/spec/unix_socket_spec.rb +108 -0
  82. data/thrift.gemspec +32 -0
  83. metadata +202 -0
@@ -0,0 +1,43 @@
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 SimpleServer < BaseServer
22
+ def serve
23
+ begin
24
+ @server_transport.listen
25
+ loop do
26
+ client = @server_transport.accept
27
+ trans = @transport_factory.get_transport(client)
28
+ prot = @protocol_factory.get_protocol(trans)
29
+ begin
30
+ loop do
31
+ @processor.process(prot, prot)
32
+ end
33
+ rescue Thrift::TransportException, Thrift::ProtocolException
34
+ ensure
35
+ trans.close
36
+ end
37
+ end
38
+ ensure
39
+ @server_transport.close
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,75 @@
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 'thread'
21
+
22
+ module Thrift
23
+ class ThreadPoolServer < BaseServer
24
+ def initialize(processor, server_transport, transport_factory=nil, protocol_factory=nil, num=20)
25
+ super(processor, server_transport, transport_factory, protocol_factory)
26
+ @thread_q = SizedQueue.new(num)
27
+ @exception_q = Queue.new
28
+ @running = false
29
+ end
30
+
31
+ ## exceptions that happen in worker threads will be relayed here and
32
+ ## must be caught. 'retry' can be used to continue. (threads will
33
+ ## continue to run while the exception is being handled.)
34
+ def rescuable_serve
35
+ Thread.new { serve } unless @running
36
+ @running = true
37
+ raise @exception_q.pop
38
+ end
39
+
40
+ ## exceptions that happen in worker threads simply cause that thread
41
+ ## to die and another to be spawned in its place.
42
+ def serve
43
+ @server_transport.listen
44
+
45
+ begin
46
+ loop do
47
+ @thread_q.push(:token)
48
+ Thread.new do
49
+ begin
50
+ loop do
51
+ client = @server_transport.accept
52
+ trans = @transport_factory.get_transport(client)
53
+ prot = @protocol_factory.get_protocol(trans)
54
+ begin
55
+ loop do
56
+ @processor.process(prot, prot)
57
+ end
58
+ rescue Thrift::TransportException, Thrift::ProtocolException => e
59
+ ensure
60
+ trans.close
61
+ end
62
+ end
63
+ rescue => e
64
+ @exception_q.push(e)
65
+ ensure
66
+ @thread_q.pop # thread died!
67
+ end
68
+ end
69
+ end
70
+ ensure
71
+ @server_transport.close
72
+ end
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,47 @@
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 'thread'
21
+
22
+ module Thrift
23
+ class ThreadedServer < BaseServer
24
+ def serve
25
+ begin
26
+ @server_transport.listen
27
+ loop do
28
+ client = @server_transport.accept
29
+ trans = @transport_factory.get_transport(client)
30
+ prot = @protocol_factory.get_protocol(trans)
31
+ Thread.new(prot, trans) do |p, t|
32
+ begin
33
+ loop do
34
+ @processor.process(p, p)
35
+ end
36
+ rescue Thrift::TransportException, Thrift::ProtocolException
37
+ ensure
38
+ t.close
39
+ end
40
+ end
41
+ end
42
+ ensure
43
+ @server_transport.close
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,298 @@
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 'set'
21
+
22
+ module Thrift
23
+ module Struct
24
+ def initialize(d={})
25
+ # get a copy of the default values to work on, removing defaults in favor of arguments
26
+ fields_with_defaults = fields_with_default_values.dup
27
+
28
+ # check if the defaults is empty, or if there are no parameters for this
29
+ # instantiation, and if so, don't bother overriding defaults.
30
+ unless fields_with_defaults.empty? || d.empty?
31
+ d.each_key do |name|
32
+ fields_with_defaults.delete(name.to_s)
33
+ end
34
+ end
35
+
36
+ # assign all the user-specified arguments
37
+ unless d.empty?
38
+ d.each do |name, value|
39
+ unless name_to_id(name.to_s)
40
+ raise Exception, "Unknown key given to #{self.class}.new: #{name}"
41
+ end
42
+ Thrift.check_type(value, struct_fields[name_to_id(name.to_s)], name) if Thrift.type_checking
43
+ instance_variable_set("@#{name}", value)
44
+ end
45
+ end
46
+
47
+ # assign all the default values
48
+ unless fields_with_defaults.empty?
49
+ fields_with_defaults.each do |name, default_value|
50
+ instance_variable_set("@#{name}", (default_value.dup rescue default_value))
51
+ end
52
+ end
53
+ end
54
+
55
+ def fields_with_default_values
56
+ fields_with_default_values = self.class.instance_variable_get("@fields_with_default_values")
57
+ unless fields_with_default_values
58
+ fields_with_default_values = {}
59
+ struct_fields.each do |fid, field_def|
60
+ unless field_def[:default].nil?
61
+ fields_with_default_values[field_def[:name]] = field_def[:default]
62
+ end
63
+ end
64
+ self.class.instance_variable_set("@fields_with_default_values", fields_with_default_values)
65
+ end
66
+ fields_with_default_values
67
+ end
68
+
69
+ def name_to_id(name)
70
+ names_to_ids = self.class.instance_variable_get("@names_to_ids")
71
+ unless names_to_ids
72
+ names_to_ids = {}
73
+ struct_fields.each do |fid, field_def|
74
+ names_to_ids[field_def[:name]] = fid
75
+ end
76
+ self.class.instance_variable_set("@names_to_ids", names_to_ids)
77
+ end
78
+ names_to_ids[name]
79
+ end
80
+
81
+ def each_field
82
+ struct_fields.keys.sort.each do |fid|
83
+ data = struct_fields[fid]
84
+ yield fid, data
85
+ end
86
+ end
87
+
88
+ def inspect(skip_optional_nulls = true)
89
+ fields = []
90
+ each_field do |fid, field_info|
91
+ name = field_info[:name]
92
+ value = instance_variable_get("@#{name}")
93
+ unless skip_optional_nulls && field_info[:optional] && value.nil?
94
+ fields << "#{name}:#{value.inspect}"
95
+ end
96
+ end
97
+ "<#{self.class} #{fields.join(", ")}>"
98
+ end
99
+
100
+ def read(iprot)
101
+ iprot.read_struct_begin
102
+ loop do
103
+ fname, ftype, fid = iprot.read_field_begin
104
+ break if (ftype == Types::STOP)
105
+ handle_message(iprot, fid, ftype)
106
+ iprot.read_field_end
107
+ end
108
+ iprot.read_struct_end
109
+ validate
110
+ end
111
+
112
+ def write(oprot)
113
+ validate
114
+ oprot.write_struct_begin(self.class.name)
115
+ each_field do |fid, field_info|
116
+ name = field_info[:name]
117
+ type = field_info[:type]
118
+ if (value = instance_variable_get("@#{name}"))
119
+ if is_container? type
120
+ oprot.write_field_begin(name, type, fid)
121
+ write_container(oprot, value, field_info)
122
+ oprot.write_field_end
123
+ else
124
+ oprot.write_field(name, type, fid, value)
125
+ end
126
+ end
127
+ end
128
+ oprot.write_field_stop
129
+ oprot.write_struct_end
130
+ end
131
+
132
+ def ==(other)
133
+ each_field do |fid, field_info|
134
+ name = field_info[:name]
135
+ return false unless self.instance_variable_get("@#{name}") == other.instance_variable_get("@#{name}")
136
+ end
137
+ true
138
+ end
139
+
140
+ def eql?(other)
141
+ self.class == other.class && self == other
142
+ end
143
+
144
+ def hash
145
+ field_values = []
146
+ each_field do |fid, field_info|
147
+ name = field_info[:name]
148
+ field_values << self.instance_variable_get("@#{name}")
149
+ end
150
+ field_values.hash
151
+ end
152
+
153
+ def differences(other)
154
+ diffs = []
155
+ unless other.is_a?(self.class)
156
+ diffs << "Different class!"
157
+ else
158
+ each_field do |fid, field_info|
159
+ name = field_info[:name]
160
+ diffs << "#{name} differs!" unless self.instance_variable_get("@#{name}") == other.instance_variable_get("@#{name}")
161
+ end
162
+ end
163
+ diffs
164
+ end
165
+
166
+ def self.field_accessor(klass, *fields)
167
+ fields.each do |field|
168
+ klass.send :attr_reader, field
169
+ klass.send :define_method, "#{field}=" do |value|
170
+ Thrift.check_type(value, klass::FIELDS.values.find { |f| f[:name].to_s == field.to_s }, field) if Thrift.type_checking
171
+ instance_variable_set("@#{field}", value)
172
+ end
173
+ end
174
+ end
175
+
176
+ protected
177
+
178
+ def self.append_features(mod)
179
+ if mod.ancestors.include? ::Exception
180
+ mod.send :class_variable_set, :'@@__thrift_struct_real_initialize', mod.instance_method(:initialize)
181
+ super
182
+ # set up our custom initializer so `raise Xception, 'message'` works
183
+ mod.send :define_method, :struct_initialize, mod.instance_method(:initialize)
184
+ mod.send :define_method, :initialize, mod.instance_method(:exception_initialize)
185
+ else
186
+ super
187
+ end
188
+ end
189
+
190
+ def exception_initialize(*args, &block)
191
+ if args.size == 1 and args.first.is_a? Hash
192
+ # looks like it's a regular Struct initialize
193
+ method(:struct_initialize).call(args.first)
194
+ else
195
+ # call the Struct initializer first with no args
196
+ # this will set our field default values
197
+ method(:struct_initialize).call()
198
+ # now give it to the exception
199
+ self.class.send(:class_variable_get, :'@@__thrift_struct_real_initialize').bind(self).call(*args, &block) if args.size > 0
200
+ # self.class.instance_method(:initialize).bind(self).call(*args, &block)
201
+ end
202
+ end
203
+
204
+ def handle_message(iprot, fid, ftype)
205
+ field = struct_fields[fid]
206
+ if field and field[:type] == ftype
207
+ value = read_field(iprot, field)
208
+ instance_variable_set("@#{field[:name]}", value)
209
+ else
210
+ iprot.skip(ftype)
211
+ end
212
+ end
213
+
214
+ def read_field(iprot, field = {})
215
+ case field[:type]
216
+ when Types::STRUCT
217
+ value = field[:class].new
218
+ value.read(iprot)
219
+ when Types::MAP
220
+ key_type, val_type, size = iprot.read_map_begin
221
+ value = {}
222
+ size.times do
223
+ k = read_field(iprot, field_info(field[:key]))
224
+ v = read_field(iprot, field_info(field[:value]))
225
+ value[k] = v
226
+ end
227
+ iprot.read_map_end
228
+ when Types::LIST
229
+ e_type, size = iprot.read_list_begin
230
+ value = Array.new(size) do |n|
231
+ read_field(iprot, field_info(field[:element]))
232
+ end
233
+ iprot.read_list_end
234
+ when Types::SET
235
+ e_type, size = iprot.read_set_begin
236
+ value = Set.new
237
+ size.times do
238
+ element = read_field(iprot, field_info(field[:element]))
239
+ value << element
240
+ end
241
+ iprot.read_set_end
242
+ else
243
+ value = iprot.read_type(field[:type])
244
+ end
245
+ value
246
+ end
247
+
248
+ def write_data(oprot, value, field)
249
+ if is_container? field[:type]
250
+ write_container(oprot, value, field)
251
+ else
252
+ oprot.write_type(field[:type], value)
253
+ end
254
+ end
255
+
256
+ def write_container(oprot, value, field = {})
257
+ case field[:type]
258
+ when Types::MAP
259
+ oprot.write_map_begin(field[:key][:type], field[:value][:type], value.size)
260
+ value.each do |k, v|
261
+ write_data(oprot, k, field[:key])
262
+ write_data(oprot, v, field[:value])
263
+ end
264
+ oprot.write_map_end
265
+ when Types::LIST
266
+ oprot.write_list_begin(field[:element][:type], value.size)
267
+ value.each do |elem|
268
+ write_data(oprot, elem, field[:element])
269
+ end
270
+ oprot.write_list_end
271
+ when Types::SET
272
+ oprot.write_set_begin(field[:element][:type], value.size)
273
+ value.each do |v,| # the , is to preserve compatibility with the old Hash-style sets
274
+ write_data(oprot, v, field[:element])
275
+ end
276
+ oprot.write_set_end
277
+ else
278
+ raise "Not a container type: #{field[:type]}"
279
+ end
280
+ end
281
+
282
+ CONTAINER_TYPES = []
283
+ CONTAINER_TYPES[Types::LIST] = true
284
+ CONTAINER_TYPES[Types::MAP] = true
285
+ CONTAINER_TYPES[Types::SET] = true
286
+ def is_container?(type)
287
+ CONTAINER_TYPES[type]
288
+ end
289
+
290
+ def field_info(field)
291
+ { :type => field[:type],
292
+ :class => field[:class],
293
+ :key => field[:key],
294
+ :value => field[:value],
295
+ :element => field[:element] }
296
+ end
297
+ end
298
+ end