sessionm-thrift 0.8.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (81) hide show
  1. data/CHANGELOG +1 -0
  2. data/README +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/server.rb +82 -0
  7. data/benchmark/thin_server.rb +44 -0
  8. data/ext/binary_protocol_accelerated.c +441 -0
  9. data/ext/binary_protocol_accelerated.h +20 -0
  10. data/ext/compact_protocol.c +618 -0
  11. data/ext/compact_protocol.h +20 -0
  12. data/ext/constants.h +96 -0
  13. data/ext/extconf.rb +30 -0
  14. data/ext/macros.h +41 -0
  15. data/ext/memory_buffer.c +131 -0
  16. data/ext/memory_buffer.h +20 -0
  17. data/ext/protocol.c +185 -0
  18. data/ext/protocol.h +20 -0
  19. data/ext/strlcpy.c +41 -0
  20. data/ext/strlcpy.h +30 -0
  21. data/ext/struct.c +691 -0
  22. data/ext/struct.h +25 -0
  23. data/ext/thrift_native.c +196 -0
  24. data/lib/thrift.rb +64 -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 +84 -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 +229 -0
  32. data/lib/thrift/protocol/binary_protocol_accelerated.rb +39 -0
  33. data/lib/thrift/protocol/compact_protocol.rb +426 -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 +305 -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 +237 -0
  43. data/lib/thrift/struct_union.rb +192 -0
  44. data/lib/thrift/thrift_native.rb +24 -0
  45. data/lib/thrift/transport/base_server_transport.rb +37 -0
  46. data/lib/thrift/transport/base_transport.rb +107 -0
  47. data/lib/thrift/transport/buffered_transport.rb +108 -0
  48. data/lib/thrift/transport/framed_transport.rb +116 -0
  49. data/lib/thrift/transport/http_client_transport.rb +51 -0
  50. data/lib/thrift/transport/io_stream_transport.rb +39 -0
  51. data/lib/thrift/transport/memory_buffer_transport.rb +125 -0
  52. data/lib/thrift/transport/server_socket.rb +63 -0
  53. data/lib/thrift/transport/socket.rb +137 -0
  54. data/lib/thrift/transport/unix_server_socket.rb +60 -0
  55. data/lib/thrift/transport/unix_socket.rb +40 -0
  56. data/lib/thrift/types.rb +101 -0
  57. data/lib/thrift/union.rb +179 -0
  58. data/spec/ThriftSpec.thrift +132 -0
  59. data/spec/base_protocol_spec.rb +160 -0
  60. data/spec/base_transport_spec.rb +351 -0
  61. data/spec/binary_protocol_accelerated_spec.rb +46 -0
  62. data/spec/binary_protocol_spec.rb +61 -0
  63. data/spec/binary_protocol_spec_shared.rb +375 -0
  64. data/spec/client_spec.rb +100 -0
  65. data/spec/compact_protocol_spec.rb +144 -0
  66. data/spec/exception_spec.rb +142 -0
  67. data/spec/http_client_spec.rb +64 -0
  68. data/spec/mongrel_http_server_spec.rb +117 -0
  69. data/spec/nonblocking_server_spec.rb +265 -0
  70. data/spec/processor_spec.rb +83 -0
  71. data/spec/serializer_spec.rb +69 -0
  72. data/spec/server_socket_spec.rb +80 -0
  73. data/spec/server_spec.rb +159 -0
  74. data/spec/socket_spec.rb +61 -0
  75. data/spec/socket_spec_shared.rb +104 -0
  76. data/spec/spec_helper.rb +58 -0
  77. data/spec/struct_spec.rb +295 -0
  78. data/spec/types_spec.rb +116 -0
  79. data/spec/union_spec.rb +193 -0
  80. data/spec/unix_socket_spec.rb +108 -0
  81. metadata +247 -0
@@ -0,0 +1,39 @@
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
+ =begin
21
+ The only change required for a transport to support BinaryProtocolAccelerated is to implement 2 methods:
22
+ * borrow(size), which takes an optional argument and returns atleast _size_ bytes from the transport,
23
+ or the default buffer size if no argument is given
24
+ * consume!(size), which removes size bytes from the front of the buffer
25
+
26
+ See MemoryBuffer and BufferedTransport for examples.
27
+ =end
28
+
29
+ module Thrift
30
+ class BinaryProtocolAcceleratedFactory < BaseProtocolFactory
31
+ def get_protocol(trans)
32
+ if (defined? BinaryProtocolAccelerated)
33
+ BinaryProtocolAccelerated.new(trans)
34
+ else
35
+ BinaryProtocol.new(trans)
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,426 @@
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 CompactProtocol < BaseProtocol
22
+
23
+ PROTOCOL_ID = [0x82].pack('c').unpack('c').first
24
+ VERSION = 1
25
+ VERSION_MASK = 0x1f
26
+ TYPE_MASK = 0xE0
27
+ TYPE_SHIFT_AMOUNT = 5
28
+
29
+ TSTOP = ["", Types::STOP, 0]
30
+
31
+ #
32
+ # All of the on-wire type codes.
33
+ #
34
+ class CompactTypes
35
+ BOOLEAN_TRUE = 0x01
36
+ BOOLEAN_FALSE = 0x02
37
+ BYTE = 0x03
38
+ I16 = 0x04
39
+ I32 = 0x05
40
+ I64 = 0x06
41
+ DOUBLE = 0x07
42
+ BINARY = 0x08
43
+ LIST = 0x09
44
+ SET = 0x0A
45
+ MAP = 0x0B
46
+ STRUCT = 0x0C
47
+
48
+ def self.is_bool_type?(b)
49
+ (b & 0x0f) == BOOLEAN_TRUE || (b & 0x0f) == BOOLEAN_FALSE
50
+ end
51
+
52
+ COMPACT_TO_TTYPE = {
53
+ Types::STOP => Types::STOP,
54
+ BOOLEAN_FALSE => Types::BOOL,
55
+ BOOLEAN_TRUE => Types::BOOL,
56
+ BYTE => Types::BYTE,
57
+ I16 => Types::I16,
58
+ I32 => Types::I32,
59
+ I64 => Types::I64,
60
+ DOUBLE => Types::DOUBLE,
61
+ BINARY => Types::STRING,
62
+ LIST => Types::LIST,
63
+ SET => Types::SET,
64
+ MAP => Types::MAP,
65
+ STRUCT => Types::STRUCT
66
+ }
67
+
68
+ TTYPE_TO_COMPACT = {
69
+ Types::STOP => Types::STOP,
70
+ Types::BOOL => BOOLEAN_TRUE,
71
+ Types::BYTE => BYTE,
72
+ Types::I16 => I16,
73
+ Types::I32 => I32,
74
+ Types::I64 => I64,
75
+ Types::DOUBLE => DOUBLE,
76
+ Types::STRING => BINARY,
77
+ Types::LIST => LIST,
78
+ Types::SET => SET,
79
+ Types::MAP => MAP,
80
+ Types::STRUCT => STRUCT
81
+ }
82
+
83
+ def self.get_ttype(compact_type)
84
+ val = COMPACT_TO_TTYPE[compact_type & 0x0f]
85
+ raise "don't know what type: #{compact_type & 0x0f}" unless val
86
+ val
87
+ end
88
+
89
+ def self.get_compact_type(ttype)
90
+ val = TTYPE_TO_COMPACT[ttype]
91
+ raise "don't know what type: #{ttype & 0x0f}" unless val
92
+ val
93
+ end
94
+ end
95
+
96
+ def initialize(transport)
97
+ super(transport)
98
+
99
+ @last_field = [0]
100
+ @boolean_value = nil
101
+
102
+ # Pre-allocated read buffer for read_double().
103
+ @rbuf = "\0" * 8
104
+ @rbuf.force_encoding("BINARY") if @rbuf.respond_to?(:force_encoding)
105
+ end
106
+
107
+ def write_message_begin(name, type, seqid)
108
+ write_byte(PROTOCOL_ID)
109
+ write_byte((VERSION & VERSION_MASK) | ((type << TYPE_SHIFT_AMOUNT) & TYPE_MASK))
110
+ write_varint32(seqid)
111
+ write_string(name)
112
+ nil
113
+ end
114
+
115
+ def write_struct_begin(name)
116
+ @last_field.push(0)
117
+ nil
118
+ end
119
+
120
+ def write_struct_end
121
+ @last_field.pop
122
+ nil
123
+ end
124
+
125
+ def write_field_begin(name, type, id)
126
+ if type == Types::BOOL
127
+ # we want to possibly include the value, so we'll wait.
128
+ @boolean_field = [type, id]
129
+ else
130
+ write_field_begin_internal(type, id)
131
+ end
132
+ nil
133
+ end
134
+
135
+ #
136
+ # The workhorse of writeFieldBegin. It has the option of doing a
137
+ # 'type override' of the type header. This is used specifically in the
138
+ # boolean field case.
139
+ #
140
+ def write_field_begin_internal(type, id, type_override=nil)
141
+ last_id = @last_field.pop
142
+
143
+ # if there's a type override, use that.
144
+ typeToWrite = type_override || CompactTypes.get_compact_type(type)
145
+
146
+ # check if we can use delta encoding for the field id
147
+ if id > last_id && id - last_id <= 15
148
+ # write them together
149
+ write_byte((id - last_id) << 4 | typeToWrite)
150
+ else
151
+ # write them separate
152
+ write_byte(typeToWrite)
153
+ write_i16(id)
154
+ end
155
+
156
+ @last_field.push(id)
157
+ nil
158
+ end
159
+
160
+ def write_field_stop
161
+ write_byte(Types::STOP)
162
+ end
163
+
164
+ def write_map_begin(ktype, vtype, size)
165
+ if (size == 0)
166
+ write_byte(0)
167
+ else
168
+ write_varint32(size)
169
+ write_byte(CompactTypes.get_compact_type(ktype) << 4 | CompactTypes.get_compact_type(vtype))
170
+ end
171
+ end
172
+
173
+ def write_list_begin(etype, size)
174
+ write_collection_begin(etype, size)
175
+ end
176
+
177
+ def write_set_begin(etype, size)
178
+ write_collection_begin(etype, size);
179
+ end
180
+
181
+ def write_bool(bool)
182
+ type = bool ? CompactTypes::BOOLEAN_TRUE : CompactTypes::BOOLEAN_FALSE
183
+ unless @boolean_field.nil?
184
+ # we haven't written the field header yet
185
+ write_field_begin_internal(@boolean_field.first, @boolean_field.last, type)
186
+ @boolean_field = nil
187
+ else
188
+ # we're not part of a field, so just write the value.
189
+ write_byte(type)
190
+ end
191
+ end
192
+
193
+ def write_byte(byte)
194
+ @trans.write([byte].pack('c'))
195
+ end
196
+
197
+ def write_i16(i16)
198
+ write_varint32(int_to_zig_zag(i16))
199
+ end
200
+
201
+ def write_i32(i32)
202
+ write_varint32(int_to_zig_zag(i32))
203
+ end
204
+
205
+ def write_i64(i64)
206
+ write_varint64(long_to_zig_zag(i64))
207
+ end
208
+
209
+ def write_double(dub)
210
+ @trans.write([dub].pack("G").reverse)
211
+ end
212
+
213
+ def write_string(str)
214
+ write_varint32(str.length)
215
+ @trans.write(str)
216
+ end
217
+
218
+ def read_message_begin
219
+ protocol_id = read_byte()
220
+ if protocol_id != PROTOCOL_ID
221
+ raise ProtocolException.new("Expected protocol id #{PROTOCOL_ID} but got #{protocol_id}")
222
+ end
223
+
224
+ version_and_type = read_byte()
225
+ version = version_and_type & VERSION_MASK
226
+ if (version != VERSION)
227
+ raise ProtocolException.new("Expected version #{VERSION} but got #{version}");
228
+ end
229
+
230
+ type = (version_and_type >> TYPE_SHIFT_AMOUNT) & 0x03
231
+ seqid = read_varint32()
232
+ messageName = read_string()
233
+ [messageName, type, seqid]
234
+ end
235
+
236
+ def read_struct_begin
237
+ @last_field.push(0)
238
+ ""
239
+ end
240
+
241
+ def read_struct_end
242
+ @last_field.pop()
243
+ nil
244
+ end
245
+
246
+ def read_field_begin
247
+ type = read_byte()
248
+
249
+ # if it's a stop, then we can return immediately, as the struct is over.
250
+ if (type & 0x0f) == Types::STOP
251
+ TSTOP
252
+ else
253
+ field_id = nil
254
+
255
+ # mask off the 4 MSB of the type header. it could contain a field id delta.
256
+ modifier = (type & 0xf0) >> 4
257
+ if modifier == 0
258
+ # not a delta. look ahead for the zigzag varint field id.
259
+ @last_field.pop
260
+ field_id = read_i16()
261
+ else
262
+ # has a delta. add the delta to the last read field id.
263
+ field_id = @last_field.pop + modifier
264
+ end
265
+
266
+ # if this happens to be a boolean field, the value is encoded in the type
267
+ if CompactTypes.is_bool_type?(type)
268
+ # save the boolean value in a special instance variable.
269
+ @bool_value = (type & 0x0f) == CompactTypes::BOOLEAN_TRUE
270
+ end
271
+
272
+ # push the new field onto the field stack so we can keep the deltas going.
273
+ @last_field.push(field_id)
274
+ ["", CompactTypes.get_ttype(type & 0x0f), field_id]
275
+ end
276
+ end
277
+
278
+ def read_map_begin
279
+ size = read_varint32()
280
+ key_and_value_type = size == 0 ? 0 : read_byte()
281
+ [CompactTypes.get_ttype(key_and_value_type >> 4), CompactTypes.get_ttype(key_and_value_type & 0xf), size]
282
+ end
283
+
284
+ def read_list_begin
285
+ size_and_type = read_byte()
286
+ size = (size_and_type >> 4) & 0x0f
287
+ if size == 15
288
+ size = read_varint32()
289
+ end
290
+ type = CompactTypes.get_ttype(size_and_type)
291
+ [type, size]
292
+ end
293
+
294
+ def read_set_begin
295
+ read_list_begin
296
+ end
297
+
298
+ def read_bool
299
+ unless @bool_value.nil?
300
+ bv = @bool_value
301
+ @bool_value = nil
302
+ bv
303
+ else
304
+ read_byte() == CompactTypes::BOOLEAN_TRUE
305
+ end
306
+ end
307
+
308
+ def read_byte
309
+ val = trans.read_byte
310
+ if (val > 0x7f)
311
+ val = 0 - ((val - 1) ^ 0xff)
312
+ end
313
+ val
314
+ end
315
+
316
+ def read_i16
317
+ zig_zag_to_int(read_varint32())
318
+ end
319
+
320
+ def read_i32
321
+ zig_zag_to_int(read_varint32())
322
+ end
323
+
324
+ def read_i64
325
+ zig_zag_to_long(read_varint64())
326
+ end
327
+
328
+ def read_double
329
+ trans.read_into_buffer(@rbuf, 8)
330
+ val = @rbuf.reverse.unpack('G').first
331
+ val
332
+ end
333
+
334
+ def read_string
335
+ size = read_varint32()
336
+ trans.read_all(size)
337
+ end
338
+
339
+
340
+ private
341
+
342
+ #
343
+ # Abstract method for writing the start of lists and sets. List and sets on
344
+ # the wire differ only by the type indicator.
345
+ #
346
+ def write_collection_begin(elem_type, size)
347
+ if size <= 14
348
+ write_byte(size << 4 | CompactTypes.get_compact_type(elem_type))
349
+ else
350
+ write_byte(0xf0 | CompactTypes.get_compact_type(elem_type))
351
+ write_varint32(size)
352
+ end
353
+ end
354
+
355
+ def write_varint32(n)
356
+ # int idx = 0;
357
+ while true
358
+ if (n & ~0x7F) == 0
359
+ # i32buf[idx++] = (byte)n;
360
+ write_byte(n)
361
+ break
362
+ # return;
363
+ else
364
+ # i32buf[idx++] = (byte)((n & 0x7F) | 0x80);
365
+ write_byte((n & 0x7F) | 0x80)
366
+ n = n >> 7
367
+ end
368
+ end
369
+ # trans_.write(i32buf, 0, idx);
370
+ end
371
+
372
+ SEVEN_BIT_MASK = 0x7F
373
+ EVERYTHING_ELSE_MASK = ~SEVEN_BIT_MASK
374
+
375
+ def write_varint64(n)
376
+ while true
377
+ if (n & EVERYTHING_ELSE_MASK) == 0 #TODO need to find a way to make this into a long...
378
+ write_byte(n)
379
+ break
380
+ else
381
+ write_byte((n & SEVEN_BIT_MASK) | 0x80)
382
+ n >>= 7
383
+ end
384
+ end
385
+ end
386
+
387
+ def read_varint32()
388
+ read_varint64()
389
+ end
390
+
391
+ def read_varint64()
392
+ shift = 0
393
+ result = 0
394
+ while true
395
+ b = read_byte()
396
+ result |= (b & 0x7f) << shift
397
+ break if (b & 0x80) != 0x80
398
+ shift += 7
399
+ end
400
+ result
401
+ end
402
+
403
+ def int_to_zig_zag(n)
404
+ (n << 1) ^ (n >> 31)
405
+ end
406
+
407
+ def long_to_zig_zag(l)
408
+ # puts "zz encoded #{l} to #{(l << 1) ^ (l >> 63)}"
409
+ (l << 1) ^ (l >> 63)
410
+ end
411
+
412
+ def zig_zag_to_int(n)
413
+ (n >> 1) ^ -(n & 1)
414
+ end
415
+
416
+ def zig_zag_to_long(n)
417
+ (n >> 1) ^ -(n & 1)
418
+ end
419
+ end
420
+
421
+ class CompactProtocolFactory < BaseProtocolFactory
422
+ def get_protocol(trans)
423
+ CompactProtocol.new(trans)
424
+ end
425
+ end
426
+ end