bones-rpc 0.0.2 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (56) hide show
  1. checksums.yaml +4 -4
  2. data/.ruby-gemset +1 -1
  3. data/.ruby-version +1 -1
  4. data/bones-rpc.gemspec +1 -4
  5. data/lib/bones/rpc.rb +1 -1
  6. data/lib/bones/rpc/adapter.rb +44 -4
  7. data/lib/bones/rpc/adapter/json.rb +66 -0
  8. data/lib/bones/rpc/address.rb +6 -4
  9. data/lib/bones/rpc/backend.rb +31 -0
  10. data/lib/bones/rpc/backend/base.rb +30 -0
  11. data/lib/bones/rpc/backend/synchronous.rb +29 -0
  12. data/lib/bones/rpc/cluster.rb +18 -18
  13. data/lib/bones/rpc/connection.rb +19 -15
  14. data/lib/bones/rpc/connection/socket.rb +0 -2
  15. data/lib/bones/rpc/connection/socket/connectable.rb +15 -11
  16. data/lib/bones/rpc/context.rb +2 -2
  17. data/lib/bones/rpc/dns_resolver.rb +85 -0
  18. data/lib/bones/rpc/errors.rb +3 -0
  19. data/lib/bones/rpc/failover.rb +3 -3
  20. data/lib/bones/rpc/failover/disconnect.rb +2 -2
  21. data/lib/bones/rpc/failover/ignore.rb +2 -2
  22. data/lib/bones/rpc/failover/retry.rb +2 -2
  23. data/lib/bones/rpc/instrumentable.rb +3 -3
  24. data/lib/bones/rpc/instrumentable/log.rb +2 -2
  25. data/lib/bones/rpc/instrumentable/noop.rb +2 -2
  26. data/lib/bones/rpc/loggable.rb +8 -8
  27. data/lib/bones/rpc/node.rb +47 -37
  28. data/lib/bones/rpc/node/registry.rb +4 -0
  29. data/lib/bones/rpc/parser.rb +16 -5
  30. data/lib/bones/rpc/parser/buffer.rb +6 -2
  31. data/lib/bones/rpc/protocol/adapter_helper.rb +2 -2
  32. data/lib/bones/rpc/protocol/binary_helper.rb +2 -2
  33. data/lib/bones/rpc/read_preference.rb +3 -3
  34. data/lib/bones/rpc/read_preference/nearest.rb +3 -3
  35. data/lib/bones/rpc/read_preference/selectable.rb +4 -4
  36. data/lib/bones/rpc/readable.rb +4 -4
  37. data/lib/bones/rpc/session.rb +25 -16
  38. data/lib/bones/rpc/synchronous.rb +2 -0
  39. data/lib/bones/rpc/synchronous/connection.rb +36 -0
  40. data/lib/bones/rpc/synchronous/connection/reader.rb +59 -0
  41. data/lib/bones/rpc/synchronous/connection/socket.rb +4 -0
  42. data/lib/bones/rpc/synchronous/connection/socket/ssl.rb +57 -0
  43. data/lib/bones/rpc/synchronous/connection/socket/tcp.rb +30 -0
  44. data/lib/bones/rpc/synchronous/connection/writer.rb +86 -0
  45. data/lib/bones/rpc/synchronous/future.rb +91 -0
  46. data/lib/bones/rpc/synchronous/node.rb +45 -0
  47. data/lib/bones/rpc/uri.rb +20 -20
  48. data/lib/bones/rpc/version.rb +1 -1
  49. metadata +16 -52
  50. data/lib/bones/rpc/adapter/erlang.rb +0 -28
  51. data/lib/bones/rpc/adapter/msgpack.rb +0 -52
  52. data/lib/bones/rpc/connection/reader.rb +0 -49
  53. data/lib/bones/rpc/connection/socket/ssl.rb +0 -35
  54. data/lib/bones/rpc/connection/socket/tcp.rb +0 -28
  55. data/lib/bones/rpc/connection/writer.rb +0 -51
  56. data/lib/bones/rpc/future.rb +0 -26
@@ -4,7 +4,7 @@ module Bones
4
4
 
5
5
  # Contains behaviour for logging.
6
6
  #
7
- # @since 1.0.0
7
+ # @since 0.0.1
8
8
  module Loggable
9
9
 
10
10
  # Log the provided operations.
@@ -16,7 +16,7 @@ module Bones
16
16
  # @param [ Array ] ops The operations.
17
17
  # @param [ String ] runtime The runtime in formatted ms.
18
18
  #
19
- # @since 2.0.0
19
+ # @since 0.0.1
20
20
  def self.log_operations(prefix, ops, runtime)
21
21
  indent = " "*prefix.length
22
22
  if ops.length == 1
@@ -38,7 +38,7 @@ module Bones
38
38
  # @param [ String ] payload The log operations.
39
39
  # @param [ String ] runtime The runtime in formatted ms.
40
40
  #
41
- # @since 2.0.0
41
+ # @since 0.0.1
42
42
  def self.debug(prefix, payload, runtime)
43
43
  Bones::RPC.logger.debug([ prefix, payload, "runtime: #{runtime}" ].join(' '))
44
44
  end
@@ -52,7 +52,7 @@ module Bones
52
52
  # @param [ String ] payload The log operations.
53
53
  # @param [ String ] runtime The runtime in formatted ms.
54
54
  #
55
- # @since 2.0.0
55
+ # @since 0.0.1
56
56
  def self.warn(prefix, payload, runtime)
57
57
  Bones::RPC.logger.warn([ prefix, payload, "runtime: #{runtime}" ].join(' '))
58
58
  end
@@ -64,7 +64,7 @@ module Bones
64
64
  #
65
65
  # @return [ Logger ] The logger.
66
66
  #
67
- # @since 1.0.0
67
+ # @since 0.0.1
68
68
  def logger
69
69
  return @logger if defined?(@logger)
70
70
  @logger = rails_logger || default_logger
@@ -77,7 +77,7 @@ module Bones
77
77
  #
78
78
  # @return [ Logger ] The Rails logger.
79
79
  #
80
- # @since 1.0.0
80
+ # @since 0.0.1
81
81
  def rails_logger
82
82
  defined?(Rails) && Rails.respond_to?(:logger) && Rails.logger
83
83
  end
@@ -89,7 +89,7 @@ module Bones
89
89
  #
90
90
  # @return [ Logger ] The default logger.
91
91
  #
92
- # @since 1.0.0
92
+ # @since 0.0.1
93
93
  def default_logger
94
94
  logger = Logger.new(STDOUT)
95
95
  logger.level = Logger::INFO
@@ -103,7 +103,7 @@ module Bones
103
103
  #
104
104
  # @return [ Logger ] The logger.
105
105
  #
106
- # @since 1.0.0
106
+ # @since 0.0.1
107
107
  def logger=(logger)
108
108
  @logger = logger
109
109
  end
@@ -2,7 +2,6 @@
2
2
  require 'bones/rpc/address'
3
3
  require 'bones/rpc/connection'
4
4
  require 'bones/rpc/failover'
5
- require 'bones/rpc/future'
6
5
  require 'bones/rpc/instrumentable'
7
6
  require 'bones/rpc/node/registry'
8
7
 
@@ -11,9 +10,8 @@ module Bones
11
10
 
12
11
  # Represents a client to a node in a server cluster.
13
12
  #
14
- # @since 1.0.0
13
+ # @since 0.0.1
15
14
  class Node
16
- include Celluloid
17
15
  include Instrumentable
18
16
 
19
17
  # @!attribute address
@@ -37,15 +35,15 @@ module Bones
37
35
  #
38
36
  # @return [ true, false ] If the addresses are equal.
39
37
  #
40
- # @since 1.0.0
38
+ # @since 0.0.1
41
39
  def ==(other)
42
40
  return false unless other.is_a?(Node)
43
- id == other.id
41
+ address.resolved == other.address.resolved
44
42
  end
45
43
  alias :eql? :==
46
44
 
47
45
  def adapter
48
- @adapter ||= Adapter.get(options[:adapter] || :msgpack)
46
+ @adapter ||= Adapter.get(options[:adapter] || :json)
49
47
  end
50
48
 
51
49
  def attach(channel, id, future)
@@ -65,10 +63,10 @@ module Bones
65
63
  #
66
64
  # @return [ true ] If the connection suceeded.
67
65
  #
68
- # @since 2.0.0
66
+ # @since 0.0.1
69
67
  def connect
70
68
  start = Time.now
71
- @connection.connect
69
+ connection { |conn| conn.connect }
72
70
  @latency = Time.now - start
73
71
  @down_at = nil
74
72
  true
@@ -81,9 +79,17 @@ module Bones
81
79
  #
82
80
  # @return [ true, false ] If the node is connected or not.
83
81
  #
84
- # @since 2.0.0
82
+ # @since 0.0.1
85
83
  def connected?
86
- @connection.alive?
84
+ connection { |conn| conn.alive? }
85
+ end
86
+
87
+ def connection
88
+ if block_given?
89
+ yield @connection
90
+ else
91
+ @connection
92
+ end
87
93
  end
88
94
 
89
95
  def detach(channel, id)
@@ -97,9 +103,9 @@ module Bones
97
103
  #
98
104
  # @return [ true ] If the disconnection succeeded.
99
105
  #
100
- # @since 1.2.0
106
+ # @since 0.0.1
101
107
  def disconnect
102
- @connection.disconnect
108
+ connection { |conn| conn.disconnect }
103
109
  true
104
110
  end
105
111
 
@@ -110,7 +116,7 @@ module Bones
110
116
  #
111
117
  # @return [ Time, nil ] The time the node went down, or nil if up.
112
118
  #
113
- # @since 1.0.0
119
+ # @since 0.0.1
114
120
  def down?
115
121
  !!@down_at
116
122
  end
@@ -122,7 +128,7 @@ module Bones
122
128
  #
123
129
  # @return [ nil ] Nothing.
124
130
  #
125
- # @since 2.0.0
131
+ # @since 0.0.1
126
132
  def down
127
133
  @down_at = Time.new
128
134
  @latency = nil
@@ -141,7 +147,7 @@ module Bones
141
147
  #
142
148
  # @return [ nil ] nil.
143
149
  #
144
- # @since 1.0.0
150
+ # @since 0.0.1
145
151
  def ensure_connected(&block)
146
152
  begin
147
153
  connect unless connected?
@@ -162,7 +168,7 @@ module Bones
162
168
  def initialize(cluster, address)
163
169
  @cluster = cluster
164
170
  @address = address
165
- @connection = Connection.new(current_actor)
171
+ @connection = cluster.session.backend.connection_class.new(current_actor)
166
172
  @down_at = nil
167
173
  @refreshed_at = nil
168
174
  @latency = nil
@@ -170,7 +176,7 @@ module Bones
170
176
  @registry = Node::Registry.new
171
177
  @request_id = 0
172
178
  @synack_id = 0
173
- @address.resolve(self)
179
+ @address.resolve(current_actor)
174
180
  end
175
181
 
176
182
  # Get the node as a nice formatted string.
@@ -180,7 +186,7 @@ module Bones
180
186
  #
181
187
  # @return [ String ] The string inspection.
182
188
  #
183
- # @since 1.0.0
189
+ # @since 0.0.1
184
190
  def inspect
185
191
  "<#{self.class.name} resolved_address=#{address.resolved.inspect}>"
186
192
  end
@@ -194,7 +200,7 @@ module Bones
194
200
  #
195
201
  # @return [ true, false] Whether the node needs to be refreshed.
196
202
  #
197
- # @since 1.0.0
203
+ # @since 0.0.1
198
204
  def needs_refresh?(time)
199
205
  !refreshed_at || refreshed_at < time
200
206
  end
@@ -220,12 +226,12 @@ module Bones
220
226
  #
221
227
  # @return [ nil ] nil.
222
228
  #
223
- # @since 1.0.0
229
+ # @since 0.0.1
224
230
  def refresh
225
- if address.resolve(self)
231
+ if address.resolve(current_actor)
226
232
  begin
227
233
  @refreshed_at = Time.now
228
- if synchronize.value(timeout)
234
+ if synchronize.value(refresh_timeout)
229
235
  cluster.handle_refresh(current_actor)
230
236
  else
231
237
  down
@@ -236,24 +242,28 @@ module Bones
236
242
  end
237
243
  end
238
244
 
239
- def request(method, params)
240
- with_future(Protocol::Request.new(next_request_id, method, params))
241
- end
242
-
243
- def synchronize
244
- with_future(Protocol::Synchronize.new(next_synack_id, adapter))
245
- end
246
-
247
245
  # Get the timeout, in seconds, for this node.
248
246
  #
249
247
  # @example Get the timeout in seconds.
250
- # node.timeout
248
+ # node.refresh_timeout
251
249
  #
252
250
  # @return [ Integer ] The configured timeout or the default of 5.
253
251
  #
254
- # @since 1.0.0
255
- def timeout
256
- @timeout ||= (options[:timeout] || 5)
252
+ # @since 0.0.1
253
+ def refresh_timeout
254
+ @refresh_timeout ||= (options[:timeout] || 5)
255
+ end
256
+
257
+ def registry_empty?
258
+ @registry.empty?
259
+ end
260
+
261
+ def request(method, params)
262
+ with_future(Protocol::Request.new(next_request_id, method, params))
263
+ end
264
+
265
+ def synchronize
266
+ with_future(Protocol::Synchronize.new(next_synack_id, adapter))
257
267
  end
258
268
 
259
269
  private
@@ -271,7 +281,7 @@ module Bones
271
281
  #
272
282
  # @return [ Object ] The result of the yield.
273
283
  #
274
- # @since 2.0.0
284
+ # @since 0.0.1
275
285
  def logging(message)
276
286
  instrument(TOPIC, prefix: " BONES-RPC: #{address.resolved}", ops: [message]) do
277
287
  yield if block_given?
@@ -297,7 +307,7 @@ module Bones
297
307
  def process(message, future = nil)
298
308
  logging(message) do
299
309
  ensure_connected do
300
- @connection.write([[message, future]])
310
+ connection { |conn| conn.write([[message, future]]) }
301
311
  end
302
312
  end
303
313
  return future
@@ -306,7 +316,7 @@ module Bones
306
316
  end
307
317
 
308
318
  def with_future(message)
309
- process(message, Future.new)
319
+ process(message, cluster.session.backend.future_class.new)
310
320
  end
311
321
 
312
322
  def without_future(message)
@@ -8,6 +8,10 @@ module Bones
8
8
  @registry = {}
9
9
  end
10
10
 
11
+ def empty?
12
+ @registry.empty? || @registry.all? { |channel, child| child.empty? }
13
+ end
14
+
11
15
  def flush(exception = Errors::ConnectionFailure.new("Socket closed"))
12
16
  return true if @registry.empty?
13
17
  @registry.each do |channel, futures|
@@ -31,29 +31,32 @@ module Bones
31
31
  if b.nil?
32
32
  raise EOFError
33
33
  elsif b.start_with?(EXT8)
34
+ pos = buffer.pos
34
35
  buffer.skip(1)
35
36
  len, = buffer.read(1).unpack('C')
36
37
  type, = buffer.read(1).unpack('C')
37
38
  check_ext!(type)
38
39
  head, = buffer.read(1).unpack('C')
39
40
  data = buffer.read(len-1)
40
- parse_ext!(head, data)
41
+ parse_ext!(head, data, pos)
41
42
  elsif b.start_with?(EXT16)
43
+ pos = buffer.pos
42
44
  buffer.skip(1)
43
45
  len, = buffer.read(2).unpack('n')
44
46
  type, = buffer.read(1).unpack('C')
45
47
  check_ext!(type)
46
48
  head, = buffer.read(1).unpack('C')
47
49
  data = buffer.read(len-1)
48
- parse_ext!(head, data)
50
+ parse_ext!(head, data, pos)
49
51
  elsif b.start_with?(EXT32)
52
+ pos = buffer.pos
50
53
  buffer.skip(1)
51
54
  len, = buffer.read(4).unpack('N')
52
55
  type, = buffer.read(1).unpack('C')
53
56
  check_ext!(type)
54
57
  head, = buffer.read(1).unpack('C')
55
58
  data = buffer.read(len-1)
56
- parse_ext!(head, data)
59
+ parse_ext!(head, data, pos)
57
60
  else
58
61
  object = parser.read
59
62
  buffer.seek(parser.unpacker_pos)
@@ -88,12 +91,20 @@ module Bones
88
91
  end
89
92
  end
90
93
 
91
- def parse_ext!(head, data)
94
+ def parse_ext!(head, data, pos)
92
95
  message = Protocol.get_by_ext_head(head)
93
96
  if message
94
97
  message.unpack(data)
95
98
  else
96
- map_from!(Adapter.get_by_ext_head(head).unpack(data))
99
+ ext_adapter = Adapter.get_by_ext_head(head)
100
+ if ext_adapter == adapter
101
+ buffer.seek(pos)
102
+ object = parser.read
103
+ buffer.seek(parser.unpacker_pos)
104
+ map_from!(object)
105
+ else
106
+ raise(Errors::InvalidExtMessage, "bad ext adapter message received of type #{ext_adapter.inspect} (should be #{adapter.inspect})")
107
+ end
97
108
  end
98
109
  end
99
110
 
@@ -7,7 +7,11 @@ module Bones
7
7
  attr_reader :io
8
8
 
9
9
  def initialize(data)
10
- @io = StringIO.new(data)
10
+ @io = data.is_a?(StringIO) ? data : StringIO.new(data)
11
+ end
12
+
13
+ def getbyte
14
+ io.getbyte
11
15
  end
12
16
 
13
17
  def getc
@@ -21,7 +25,7 @@ module Bones
21
25
  def read(n)
22
26
  i = pos
23
27
  data = io.read(n)
24
- if data.bytesize < n
28
+ if data.nil? || data.bytesize < n
25
29
  seek(i)
26
30
  raise EOFError
27
31
  else
@@ -15,7 +15,7 @@ module Bones
15
15
  #
16
16
  # @return [ nil ] nil.
17
17
  #
18
- # @since 1.0.0
18
+ # @since 0.0.1
19
19
  def receive_replies(connection); end
20
20
 
21
21
  # Serializes the message and all of its fields to a new buffer or to the
@@ -28,7 +28,7 @@ module Bones
28
28
  #
29
29
  # @return [ String ] The result of serliazing this message
30
30
  #
31
- # @since 1.0.0
31
+ # @since 0.0.1
32
32
  def serialize(buffer, adapter)
33
33
  Adapter.get(adapter).serialize(process, buffer)
34
34
  end
@@ -39,7 +39,7 @@ module Bones
39
39
  #
40
40
  # @return [ nil ] nil.
41
41
  #
42
- # @since 1.0.0
42
+ # @since 0.0.1
43
43
  def receive_replies(connection); end
44
44
 
45
45
  # Serializes the message and all of its fields to a new buffer or to the
@@ -52,7 +52,7 @@ module Bones
52
52
  #
53
53
  # @return [ String ] The result of serliazing this message
54
54
  #
55
- # @since 1.0.0
55
+ # @since 0.0.1
56
56
  def serialize(buffer = "", adapter = nil)
57
57
  raise NotImplementedError, "This method is generated after calling #finalize on a message class"
58
58
  end
@@ -7,14 +7,14 @@ module Bones
7
7
 
8
8
  # Provides behaviour around getting various read preference implementations.
9
9
  #
10
- # @since 2.0.0
10
+ # @since 0.0.1
11
11
  module ReadPreference
12
12
  extend self
13
13
 
14
14
  # Hash lookup for the read preference classes based off the symbols
15
15
  # provided in configuration.
16
16
  #
17
- # @since 2.0.0
17
+ # @since 0.0.1
18
18
  PREFERENCES = {
19
19
  nearest: Nearest
20
20
  }.freeze
@@ -34,7 +34,7 @@ module Bones
34
34
  #
35
35
  # @return [ Object ] The appropriate read preference.
36
36
  #
37
- # @since 2.0.0
37
+ # @since 0.0.1
38
38
  def get(name, tags = nil)
39
39
  PREFERENCES.fetch(name.to_sym).new(tags)
40
40
  end
@@ -5,7 +5,7 @@ module Bones
5
5
 
6
6
  # Encapsulates behaviour around a nearest read preference.
7
7
  #
8
- # @since 2.0.0
8
+ # @since 0.0.1
9
9
  class Nearest
10
10
  include Selectable
11
11
 
@@ -16,7 +16,7 @@ module Bones
16
16
  #
17
17
  # @return [ Symbol ] :nearest.
18
18
  #
19
- # @since 2.0.0
19
+ # @since 0.0.1
20
20
  def name
21
21
  :nearest
22
22
  end
@@ -40,7 +40,7 @@ module Bones
40
40
  #
41
41
  # @return [ Object ] The result of the block.
42
42
  #
43
- # @since 2.0.0
43
+ # @since 0.0.1
44
44
  def with_node(cluster, &block)
45
45
  with_retry(cluster) do
46
46
  nearest = cluster.nodes.sort_by(&:latency).first