moped 1.5.3 → 2.0.0.beta

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of moped might be problematic. Click here for more details.

Files changed (90) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +42 -5
  3. data/README.md +1 -1
  4. data/lib/moped.rb +10 -13
  5. data/lib/moped/address.rb +56 -0
  6. data/lib/moped/authenticatable.rb +89 -0
  7. data/lib/moped/cluster.rb +169 -136
  8. data/lib/moped/collection.rb +53 -19
  9. data/lib/moped/connection.rb +69 -10
  10. data/lib/moped/connection/manager.rb +49 -0
  11. data/lib/moped/connection/pool.rb +198 -0
  12. data/lib/moped/connection/queue.rb +93 -0
  13. data/lib/moped/connection/reaper.rb +52 -0
  14. data/lib/moped/connection/socket.rb +4 -0
  15. data/lib/moped/connection/socket/connectable.rb +169 -0
  16. data/lib/moped/connection/socket/ssl.rb +52 -0
  17. data/lib/moped/connection/socket/tcp.rb +25 -0
  18. data/lib/moped/connection/sockets.rb +4 -0
  19. data/lib/moped/cursor.rb +3 -5
  20. data/lib/moped/database.rb +18 -24
  21. data/lib/moped/errors.rb +35 -6
  22. data/lib/moped/executable.rb +96 -0
  23. data/lib/moped/failover.rb +41 -0
  24. data/lib/moped/failover/disconnect.rb +31 -0
  25. data/lib/moped/failover/ignore.rb +29 -0
  26. data/lib/moped/failover/reconfigure.rb +34 -0
  27. data/lib/moped/failover/retry.rb +37 -0
  28. data/lib/moped/indexes.rb +4 -1
  29. data/lib/moped/instrumentable.rb +39 -0
  30. data/lib/moped/instrumentable/log.rb +43 -0
  31. data/lib/moped/instrumentable/noop.rb +31 -0
  32. data/lib/moped/loggable.rb +110 -0
  33. data/lib/moped/node.rb +316 -297
  34. data/lib/moped/operation.rb +3 -0
  35. data/lib/moped/operation/read.rb +62 -0
  36. data/lib/moped/operation/write.rb +57 -0
  37. data/lib/moped/protocol/command.rb +65 -4
  38. data/lib/moped/protocol/commands/authenticate.rb +1 -2
  39. data/lib/moped/protocol/delete.rb +16 -0
  40. data/lib/moped/protocol/get_more.rb +102 -31
  41. data/lib/moped/protocol/insert.rb +17 -0
  42. data/lib/moped/protocol/message.rb +44 -46
  43. data/lib/moped/protocol/query.rb +175 -92
  44. data/lib/moped/protocol/reply.rb +19 -8
  45. data/lib/moped/protocol/update.rb +18 -0
  46. data/lib/moped/query.rb +43 -17
  47. data/lib/moped/read_preference.rb +49 -0
  48. data/lib/moped/read_preference/nearest.rb +55 -0
  49. data/lib/moped/read_preference/primary.rb +60 -0
  50. data/lib/moped/read_preference/primary_preferred.rb +55 -0
  51. data/lib/moped/read_preference/secondary.rb +50 -0
  52. data/lib/moped/read_preference/secondary_preferred.rb +53 -0
  53. data/lib/moped/read_preference/selectable.rb +79 -0
  54. data/lib/moped/readable.rb +55 -0
  55. data/lib/moped/session.rb +122 -70
  56. data/lib/moped/{mongo_uri.rb → uri.rb} +75 -31
  57. data/lib/moped/version.rb +1 -1
  58. data/lib/moped/write_concern.rb +33 -0
  59. data/lib/moped/write_concern/propagate.rb +38 -0
  60. data/lib/moped/write_concern/unverified.rb +28 -0
  61. metadata +79 -44
  62. data/lib/moped/bson.rb +0 -45
  63. data/lib/moped/bson/binary.rb +0 -137
  64. data/lib/moped/bson/code.rb +0 -112
  65. data/lib/moped/bson/document.rb +0 -41
  66. data/lib/moped/bson/extensions.rb +0 -91
  67. data/lib/moped/bson/extensions/array.rb +0 -37
  68. data/lib/moped/bson/extensions/boolean.rb +0 -16
  69. data/lib/moped/bson/extensions/false_class.rb +0 -19
  70. data/lib/moped/bson/extensions/float.rb +0 -22
  71. data/lib/moped/bson/extensions/hash.rb +0 -39
  72. data/lib/moped/bson/extensions/integer.rb +0 -36
  73. data/lib/moped/bson/extensions/nil_class.rb +0 -19
  74. data/lib/moped/bson/extensions/object.rb +0 -11
  75. data/lib/moped/bson/extensions/regexp.rb +0 -38
  76. data/lib/moped/bson/extensions/string.rb +0 -45
  77. data/lib/moped/bson/extensions/symbol.rb +0 -33
  78. data/lib/moped/bson/extensions/time.rb +0 -23
  79. data/lib/moped/bson/extensions/true_class.rb +0 -19
  80. data/lib/moped/bson/max_key.rb +0 -51
  81. data/lib/moped/bson/min_key.rb +0 -51
  82. data/lib/moped/bson/object_id.rb +0 -301
  83. data/lib/moped/bson/timestamp.rb +0 -38
  84. data/lib/moped/bson/types.rb +0 -67
  85. data/lib/moped/logging.rb +0 -58
  86. data/lib/moped/session/context.rb +0 -115
  87. data/lib/moped/sockets/connectable.rb +0 -167
  88. data/lib/moped/sockets/ssl.rb +0 -50
  89. data/lib/moped/sockets/tcp.rb +0 -23
  90. data/lib/moped/threaded.rb +0 -69
@@ -35,6 +35,43 @@ module Moped
35
35
  #
36
36
  module Message
37
37
 
38
+ # Default implementation for a message is to do nothing when receiving
39
+ # replies.
40
+ #
41
+ # @example Receive replies.
42
+ # message.receive_replies(connection)
43
+ #
44
+ # @param [ Connection ] connection The connection.
45
+ #
46
+ # @return [ nil ] nil.
47
+ #
48
+ # @since 1.0.0
49
+ def receive_replies(connection); end
50
+
51
+ # Serializes the message and all of its fields to a new buffer or to the
52
+ # provided buffer.
53
+ #
54
+ # @example Serliaze the message.
55
+ # message.serialize
56
+ #
57
+ # @param [ String ] buffer A buffer to serialize to.
58
+ #
59
+ # @return [ String ] The result of serliazing this message
60
+ #
61
+ # @since 1.0.0
62
+ def serialize(buffer = "")
63
+ raise NotImplementedError, "This method is generated after calling #finalize on a message class"
64
+ end
65
+ alias :to_s :serialize
66
+
67
+ # @return [String] the nicely formatted version of the message
68
+ def inspect
69
+ fields = self.class.fields.map do |field|
70
+ "@#{field}=" + __send__(field).inspect
71
+ end
72
+ "#<#{self.class.name}\n" <<
73
+ " #{fields * "\n "}>"
74
+ end
38
75
  class << self
39
76
 
40
77
  # Extends the including class with +ClassMethods+.
@@ -42,10 +79,8 @@ module Moped
42
79
  # @param [Class] subclass the inheriting class
43
80
  def included(base)
44
81
  super
45
-
46
- base.extend ClassMethods
82
+ base.extend(ClassMethods)
47
83
  end
48
-
49
84
  private :included
50
85
  end
51
86
 
@@ -119,21 +154,21 @@ module Moped
119
154
  if options[:optional]
120
155
  class_eval <<-RUBY, __FILE__, __LINE__ + 1
121
156
  def serialize_#{name}(buffer)
122
- BSON::Document.serialize(#{name}, buffer) if #{name}
157
+ buffer << #{name}.to_bson if #{name}
123
158
  end
124
159
  RUBY
125
160
  elsif options[:type] == :array
126
161
  class_eval <<-RUBY, __FILE__, __LINE__ + 1
127
162
  def serialize_#{name}(buffer)
128
163
  #{name}.each do |document|
129
- BSON::Document.serialize(document, buffer)
164
+ buffer << document.to_bson
130
165
  end
131
166
  end
132
167
  RUBY
133
168
  else
134
169
  class_eval <<-RUBY, __FILE__, __LINE__ + 1
135
170
  def serialize_#{name}(buffer)
136
- BSON::Document.serialize(#{name}, buffer)
171
+ buffer << #{name}.to_bson
137
172
  end
138
173
  RUBY
139
174
  end
@@ -277,14 +312,12 @@ module Moped
277
312
  class_eval <<-EOS, __FILE__, __LINE__ + 1
278
313
  def serialize(buffer = "")
279
314
  start = buffer.bytesize
280
-
281
315
  #{fields.map { |f| "serialize_#{f}(buffer)" }.join("\n")}
282
-
283
316
  self.length = buffer.bytesize - start
284
- buffer[start, 4] = serialize_length ""
317
+ buffer[start, 4] = serialize_length("")
285
318
  buffer
286
319
  end
287
- alias to_s serialize
320
+ alias :to_s :serialize
288
321
  EOS
289
322
  end
290
323
 
@@ -294,44 +327,9 @@ module Moped
294
327
  # identical fields.
295
328
  def inherited(subclass)
296
329
  super
297
-
298
- subclass.fields.replace fields
299
- end
300
-
301
- end
302
-
303
- # Default implementation for a message is to do nothing when receiving
304
- # replies.
305
- #
306
- # @example Receive replies.
307
- # message.receive_replies(connection)
308
- #
309
- # @param [ Connection ] connection The connection.
310
- #
311
- # @since 1.0.0
312
- #
313
- # @return [ nil ] nil.
314
- def receive_replies(connection); end
315
-
316
- # Serializes the message and all of its fields to a new buffer or to the
317
- # provided buffer.
318
- #
319
- # @param [String] buffer a buffer to serialize to
320
- # @return [String] the result of serliazing this message
321
- def serialize(buffer = "")
322
- raise NotImplementedError, "This method is generated after calling #finalize on a message class"
323
- end
324
- alias to_s serialize
325
-
326
- # @return [String] the nicely formatted version of the message
327
- def inspect
328
- fields = self.class.fields.map do |field|
329
- "@#{field}=" + __send__(field).inspect
330
+ subclass.fields.replace(fields)
330
331
  end
331
- "#<#{self.class.name}\n" <<
332
- " #{fields * "\n "}>"
333
332
  end
334
-
335
333
  end
336
334
  end
337
335
  end
@@ -1,123 +1,174 @@
1
1
  module Moped
2
2
  module Protocol
3
+
3
4
  # The Protocol class for querying a collection.
4
5
  #
5
- # @example Find all users named John
6
- # Query.new "moped", "users", { name: "John" }
7
- #
8
- # @example Find all users named John skipping 5 and returning 10
9
- # Query.new "moped", "users", { name: "John" },
10
- # skip: 5, limit: 10
11
- #
12
- # @example Find all users on slave node
13
- # Query.new "moped", "users", {}, flags: [:slave_ok]
14
- #
15
- # @example Find all user ids
16
- # Query.new "moped", "users", {}, fields: { _id: 1 }
17
- #
6
+ # @since 1.0.0
18
7
  class Query
19
8
  include Message
20
9
 
21
- # @attribute
22
- # @return [Number] the length of the message
10
+ # @!attribute length
11
+ # @return [ Integer ] the length of the message
23
12
  int32 :length
24
13
 
25
- # @attribute
26
- # @return [Number] the request id of the message
14
+ # @!attribute request_id
15
+ # @return [ Integer ] the request id of the message
27
16
  int32 :request_id
28
17
 
29
18
  int32 :response_to
30
19
 
31
- # @attribute
32
- # @return [Number] the operation code of this message
20
+ # @!attribute op_code
21
+ # @return [ Integer ] the operation code of this message
33
22
  int32 :op_code
34
23
 
35
- # @attribute
24
+ # @!attribute
36
25
  # The flags for the query. Supported flags are: +:tailable+, +:slave_ok+,
37
26
  # +:no_cursor_timeout+, +:await_data+, +:exhaust+.
38
27
  #
39
- # @param [Array] flags the flags for this message
40
- # @return [Array] the flags for this message
41
- flags :flags, tailable: 2 ** 1,
42
- slave_ok: 2 ** 2,
43
- no_cursor_timeout: 2 ** 4,
44
- await_data: 2 ** 5,
45
- exhaust: 2 ** 6
46
-
47
- # @attribute
48
- # @return [String] the namespaced collection name
49
- cstring :full_collection_name
50
-
51
- # @attribute
52
- # @return [Number] the number of documents to skip
53
- int32 :skip
54
-
55
- # @attribute
56
- # @return [Number] the number of documents to return
57
- int32 :limit
58
-
59
- # @attribute
60
- # @return [Hash] the selector for this query
28
+ # @param [ Array ] flags the flags for this message
29
+ # @return [ Array ] the flags for this message
30
+ flags :flags, tailable: 2 ** 1,
31
+ slave_ok: 2 ** 2,
32
+ no_cursor_timeout: 2 ** 4,
33
+ await_data: 2 ** 5,
34
+ exhaust: 2 ** 6
35
+
36
+ # @!attribute full_collection_name
37
+ # @return [ String ] the namespaced collection name
38
+ cstring :full_collection_name
39
+
40
+ # @!attribute skip
41
+ # @return [ Integer ] the number of documents to skip
42
+ int32 :skip
43
+
44
+ # @!attribute limit
45
+ # @return [ Integer ] the number of documents to return
46
+ int32 :limit
47
+
48
+ # @!attribute selector
49
+ # @return [ Hash ] the selector for this query
61
50
  document :selector
62
51
 
63
- # @attribute
64
- # @return [Hash, nil] the fields to include in the reply
52
+ # @!attribute fields
53
+ # @return [ Hash, nil ] the fields to include in the reply
65
54
  document :fields, :optional => true
66
55
 
67
56
  finalize
68
57
 
69
- undef op_code
70
- # @return [Number] OP_QUERY operation code (2004)
71
- def op_code
72
- 2004
73
- end
58
+ # @!attribute collection
59
+ # @return [ String ] The collection to query.
60
+ # @!attribute database
61
+ # @return [ String ] The database to query
62
+ attr_reader :collection, :database
74
63
 
75
- # @return [String, Symbol] the database to query
76
- attr_reader :database
64
+ # @!attribute batch_size
65
+ # @return [ Integer ] The batch size of the results.
66
+ attr_accessor :batch_size
77
67
 
78
- # @return [String, Symbol] the collection to query
79
- attr_reader :collection
68
+ # Get the basic selector.
69
+ #
70
+ # @example Get the basic selector.
71
+ # query.basic_selector
72
+ #
73
+ # @note Sometimes, like in cases of deletion we need this since MongoDB
74
+ # does not understand $query in operations like DELETE.
75
+ #
76
+ # @return [ Hash ] The basic selector.
77
+ #
78
+ # @since 2.0.0
79
+ def basic_selector
80
+ selector["$query"] || selector
81
+ end
80
82
 
81
- attr_accessor :batch_size
83
+ # Get the exception specific to a failure of this particular operation.
84
+ #
85
+ # @example Get the failure exception.
86
+ # query.failure_exception(document)
87
+ #
88
+ # @param [ Moped::Protocol::Reply ] reply The reply from the database.
89
+ #
90
+ # @return [ Moped::Errors::QueryFailure ] The failure exception.
91
+ #
92
+ # @since 2.0.0
93
+ def failure_exception(reply)
94
+ Errors::QueryFailure.new(self, reply.documents.first)
95
+ end
96
+
97
+ # Determine if the provided reply message is a failure with respect to a
98
+ # query.
99
+ #
100
+ # @example Is the reply a query failure?
101
+ # query.failure?(reply)
102
+ #
103
+ # @param [ Reply ] reply The reply to the query.
104
+ #
105
+ # @return [ true, false ] If the reply is a failure.
106
+ #
107
+ # @since 2.0.0
108
+ def failure?(reply)
109
+ reply.query_failure?
110
+ end
82
111
 
112
+ # Set the option on the query to not timeout the cursor.
113
+ #
114
+ # @example Set the no timeout option.
115
+ # query.no_timeout = true
116
+ #
117
+ # @param [ true, false ] enable Whether to enable the no timeout option.
118
+ #
119
+ # @since 1.3.0
83
120
  def no_timeout=(enable)
84
121
  @flags |= [:no_cursor_timeout] if enable
85
122
  end
86
123
 
87
- # Create a new query command.
88
- #
89
- # @example
90
- # Query.new "moped", "users", { name: "John" },
91
- # skip: 5,
92
- # limit: 10,
93
- # request_id: 12930,
94
- # fields: { _id: -1, name: 1 }
95
- #
96
- # @param [String, Symbol] database the database to insert into
97
- # @param [String, Symbol] collection the collection to insert into
98
- # @param [Hash] selector the query
99
- # @param [Hash] options additional options
100
- # @option options [Number] :request_id the command's request id
101
- # @option options [Number] :skip the number of documents to skip
102
- # @option options [Number] :limit the number of documents to return
103
- # @option options [Hash] :fields the fields to return
104
- # @option options [Array] :flags the flags for querying. Supported
105
- # flags: +:tailable+, +:slave_ok+, +:no_cursor_timeout+, +:await_data+,
106
- # +:exhaust+.
124
+ # Instantiate a new query operation.
125
+ #
126
+ # @example Find all users named John.
127
+ # Query.new("moped", "users", { name: "John" })
128
+ #
129
+ # @example Find all users named John skipping 5 and returning 10.
130
+ # Query.new("moped", "users", { name: "John" }, skip: 5, limit: 10)
131
+ #
132
+ # @example Find all users on slave node.
133
+ # Query.new("moped", "users", {}, flags: [ :slave_ok ])
134
+ #
135
+ # @example Find all user ids.
136
+ # Query.new("moped", "users", {}, fields: { _id: 1 })
137
+ #
138
+ # @param [ String, Symbol ] database The database to query.
139
+ # @param [ String, Symbol ] collection The collection to query.
140
+ # @param [ Hash ] selector The query selector.
141
+ # @param [ Hash ] options The additional query options.
142
+ #
143
+ # @option options [ Integer ] :request_id The operation's request id.
144
+ # @option options [ Integer ] :skip The number of documents to skip.
145
+ # @option options [ Integer ] :limit The number of documents to return.
146
+ # @option options [ Hash ] :fields The limited fields to return.
147
+ # @option options [ Array ] :flags The flags for querying. Supported flags
148
+ # are: :tailable, :slave_ok, :no_cursor_timeout, :await_data, :exhaust.
149
+ #
150
+ # @since 1.0.0
107
151
  def initialize(database, collection, selector, options = {})
108
152
  @database = database
109
153
  @collection = collection
110
-
111
154
  @full_collection_name = "#{database}.#{collection}"
112
- @selector = selector
113
- @request_id = options[:request_id]
114
- @flags = options[:flags] || []
115
- @limit = options[:limit]
116
- @skip = options[:skip]
117
- @fields = options[:fields]
118
- @batch_size = options[:batch_size]
155
+ @selector = selector
156
+ @request_id = options[:request_id]
157
+ @flags = options[:flags] || []
158
+ @limit = options[:limit]
159
+ @skip = options[:skip]
160
+ @fields = options[:fields]
161
+ @batch_size = options[:batch_size]
119
162
  end
120
163
 
164
+ # Provide the value that will be logged when the query runs.
165
+ #
166
+ # @example Provide the log inspection.
167
+ # query.log_inspect
168
+ #
169
+ # @return [ String ] The string value for logging.
170
+ #
171
+ # @since 1.0.0
121
172
  def log_inspect
122
173
  type = "QUERY"
123
174
  fields = []
@@ -134,19 +185,18 @@ module Moped
134
185
  f.join(" ") % v
135
186
  end
136
187
 
137
- # Get the basic selector.
138
- #
139
- # @example Get the basic selector.
140
- # query.basic_selector
188
+ undef op_code
189
+
190
+ # Get the code for a query operation.
141
191
  #
142
- # @note Sometimes, like in cases of deletion we need this since MongoDB
143
- # does not understand $query in operations like DELETE.
192
+ # @example Get the operation code.
193
+ # query.op_code
144
194
  #
145
- # @return [ Hash ] The basic selector.
195
+ # @return [ Integer ] OP_QUERY operation code (2004).
146
196
  #
147
- # @since 2.0.0
148
- def basic_selector
149
- selector["$query"] || selector
197
+ # @since 1.0.0
198
+ def op_code
199
+ 2004
150
200
  end
151
201
 
152
202
  # Receive replies to the message.
@@ -162,6 +212,39 @@ module Moped
162
212
  def receive_replies(connection)
163
213
  connection.read
164
214
  end
215
+
216
+ # Take the provided reply and return the expected results to api
217
+ # consumers.
218
+ #
219
+ # @example Get the expected results of the reply.
220
+ # query.results(reply)
221
+ #
222
+ # @param [ Moped::Protocol::Reply ] reply The reply from the database.
223
+ #
224
+ # @return [ Moped::Protocol::Reply ] The reply.
225
+ #
226
+ # @since 2.0.0
227
+ def results(reply)
228
+ reply
229
+ end
230
+
231
+ private
232
+
233
+ # Duplicate the attributes in the query that need to be.
234
+ #
235
+ # @api private
236
+ #
237
+ # @example Clone the query.
238
+ # query.clone
239
+ #
240
+ # @param [ Query ] The query that was cloned from.
241
+ #
242
+ # @since 2.0.0
243
+ def initialize_copy(_)
244
+ @selector = selector.dup
245
+ @flags = flags.dup
246
+ @fields = fields.dup if fields
247
+ end
165
248
  end
166
249
  end
167
250
  end