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
@@ -0,0 +1,53 @@
1
+ # encoding: utf-8
2
+ module Moped
3
+ module ReadPreference
4
+
5
+ # Encapsulates behaviour around a secondary read preference.
6
+ #
7
+ # @since 2.0.0
8
+ class SecondaryPreferred
9
+ include Selectable
10
+
11
+ # Get the name for the read preference on the server side.
12
+ #
13
+ # @example Get the name of the read preference.
14
+ # secondary_preferred.name
15
+ #
16
+ # @return [ Symbol ] :secondaryPreferred.
17
+ #
18
+ # @since 2.0.0
19
+ def name
20
+ :secondaryPreferred
21
+ end
22
+
23
+ # Select a secondary node from the cluster. If no secondary is available then
24
+ # use a primary. If no primary is found then an exception will be raised.
25
+ #
26
+ # @example Read a secondary or primary node from the cluster.
27
+ # preference.with_node(cluster) do |node|
28
+ # node.command(ismaster: 1)
29
+ # end
30
+ #
31
+ # @note If tag sets are provided then secondary selection will need to
32
+ # match the provided tags.
33
+ #
34
+ # @param [ Cluster ] cluster The cluster of nodes to select from.
35
+ #
36
+ # @raise [ Errors::ConnectionFailure ] If no secondary or primary node was
37
+ # available in the cluster.
38
+ #
39
+ # @return [ Object ] The result of the block.
40
+ #
41
+ # @since 2.0.0
42
+ def with_node(cluster, &block)
43
+ with_retry(cluster) do
44
+ begin
45
+ cluster.with_secondary(&block)
46
+ rescue Errors::ConnectionFailure
47
+ cluster.with_primary(&block)
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,79 @@
1
+ # encoding: utf-8
2
+ module Moped
3
+ module ReadPreference
4
+
5
+ # Provides the shared behaviour for read preferences that can filter by a
6
+ # tag set or add query options.
7
+ #
8
+ # @since 2.0.0
9
+ module Selectable
10
+
11
+ # @!attribute tags
12
+ # @return [ Array<Hash> ] The tag sets.
13
+ attr_reader :tags
14
+
15
+ # Instantiate the new taggable read preference.
16
+ #
17
+ # @example Instantiate the taggable.
18
+ # Moped::ReadPreference::Secondary.new({ east_coast: 1 })
19
+ #
20
+ # @param [ Array<Hash> ] tags The tag sets.
21
+ #
22
+ # @since 2.0.0
23
+ def initialize(tags = nil)
24
+ @tags = tags
25
+ end
26
+
27
+ # Get the provided options as query options for this read preference.
28
+ #
29
+ # @example Get the query options.
30
+ # preference.query_options({})
31
+ #
32
+ # @param [ Hash ] options The existing options for the query.
33
+ #
34
+ # @return [ Hash ] The options plus additional query options.
35
+ #
36
+ # @since 2.0.0
37
+ def query_options(options)
38
+ options[:flags] ||= []
39
+ options[:flags] |= [ :slave_ok ]
40
+ options
41
+ end
42
+
43
+ private
44
+
45
+ # Execute the provided block on the cluster and retry if the execution
46
+ # fails.
47
+ #
48
+ # @api private
49
+ #
50
+ # @example Execute with retry.
51
+ # preference.with_retry(cluster) do
52
+ # cluster.with_primary do |node|
53
+ # node.refresh
54
+ # end
55
+ # end
56
+ #
57
+ # @param [ Cluster ] cluster The cluster.
58
+ # @param [ Integer ] retries The number of times to retry.
59
+ #
60
+ # @return [ Object ] The result of the block.
61
+ #
62
+ # @since 2.0.0
63
+ def with_retry(cluster, retries = cluster.max_retries, &block)
64
+ begin
65
+ block.call
66
+ rescue Errors::ConnectionFailure => e
67
+ if retries > 0
68
+ Loggable.warn(" MOPED:", "Retrying connection attempt #{retries} more time(s).", "n/a")
69
+ sleep(cluster.retry_interval)
70
+ cluster.refresh
71
+ with_retry(cluster, retries - 1, &block)
72
+ else
73
+ raise e
74
+ end
75
+ end
76
+ end
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,55 @@
1
+ # encoding: utf-8
2
+ module Moped
3
+
4
+ # Provides behaviour around readable objects.
5
+ #
6
+ # @since 2.0.0
7
+ module Readable
8
+
9
+ private
10
+
11
+ # Convenience method for getting the cluster from the session.
12
+ #
13
+ # @api private
14
+ #
15
+ # @example Get the cluster from the session.
16
+ # database.cluster
17
+ #
18
+ # @return [ Cluster ] The cluster.
19
+ #
20
+ # @since 2.0.0
21
+ def cluster
22
+ session.cluster
23
+ end
24
+
25
+ # Convenience method for getting the read preference from the session.
26
+ #
27
+ # @api private
28
+ #
29
+ # @example Get the read preference.
30
+ # database.read_preference
31
+ #
32
+ # @return [ Object ] The session's read preference.
33
+ #
34
+ # @since 2.0.0
35
+ def read_preference
36
+ session.read_preference
37
+ end
38
+
39
+ # Get the query options from the read preference.
40
+ #
41
+ # @api private
42
+ #
43
+ # @example Get the query options.
44
+ # database.query_options
45
+ #
46
+ # @param [ Hash ] options The existing options on the query.
47
+ #
48
+ # @return [ Hash ] The new query options.
49
+ #
50
+ # @since 2.0.0
51
+ def query_options(options = {})
52
+ read_preference.query_options(options)
53
+ end
54
+ end
55
+ end
data/lib/moped/session.rb CHANGED
@@ -1,3 +1,11 @@
1
+ # encoding: utf-8
2
+ require "moped/read_preference"
3
+ require "moped/readable"
4
+ require "moped/write_concern"
5
+ require "moped/collection"
6
+ require "moped/cluster"
7
+ require "moped/database"
8
+
1
9
  module Moped
2
10
 
3
11
  # A session in moped is root for all interactions with a MongoDB server or
@@ -8,31 +16,28 @@ module Moped
8
16
  #
9
17
  # @example Single database (console-style)
10
18
  # session = Moped::Session.new(["127.0.0.1:27017"])
11
- # session.use :moped
12
- # session[:users].find.one # => { name: "John" }
19
+ # session.use(:moped)
20
+ # session[:users].find.one
13
21
  #
14
22
  # @example Multiple databases
15
23
  # session = Moped::Session.new(["127.0.0.1:27017"])
16
- #
17
24
  # session.with(database: :admin) do |admin|
18
- # admin.command ismaster: 1
19
- # end
20
- #
21
- # session.with(database: :moped) do |moped|
22
- # moped[:users].find.one # => { name: "John" }
25
+ # admin.command(ismaster: 1)
23
26
  # end
24
27
  #
25
28
  # @example Authentication
26
- #
27
29
  # session = Moped::Session.new %w[127.0.0.1:27017],
28
30
  # session.with(database: "admin").login("admin", "s3cr3t")
29
31
  #
32
+ # @since 1.0.0
30
33
  class Session
34
+ include Optionable
31
35
 
32
- # @attribute [r] cluster The session cluster.
33
- # @attribute [r] context The session context.
34
- # @attribute [r] options The session options.
35
- attr_reader :cluster, :context, :options
36
+ # @!attribute cluster
37
+ # @return [ Cluster ] The cluster of nodes.
38
+ # @!attribute options
39
+ # @return [ Hash ] The configuration options.
40
+ attr_reader :cluster, :options
36
41
 
37
42
  # Return +collection+ from the current database.
38
43
  #
@@ -164,54 +169,91 @@ module Moped
164
169
  current_database.logout
165
170
  end
166
171
 
167
- # Get the session's consistency.
172
+ # Setup validation of allowed write concern options.
173
+ #
174
+ # @since 2.0.0
175
+ option(:write).allow({ w: Optionable.any(Integer) }, { "w" => Optionable.any(Integer) })
176
+ option(:write).allow({ w: Optionable.any(String) }, { "w" => Optionable.any(String) })
177
+ option(:write).allow({ j: true }, { "j" => true })
178
+ option(:write).allow({ j: false }, { "j" => false })
179
+ option(:write).allow({ fsync: true }, { "fsync" => true })
180
+ option(:write).allow({ fsync: false }, { "fsync" => false })
181
+
182
+ # Setup validation of allowed read preference options.
183
+ #
184
+ # @since 2.0.0
185
+ option(:read).allow(
186
+ :nearest,
187
+ :primary,
188
+ :primary_preferred,
189
+ :secondary,
190
+ :secondary_preferred,
191
+ "nearest",
192
+ "primary",
193
+ "primary_preferred",
194
+ "secondary",
195
+ "secondary_preferred"
196
+ )
197
+
198
+ # Setup validation of allowed database options. (Any string or symbol)
168
199
  #
169
- # @example Get the session consistency.
170
- # session.consistency
200
+ # @since 2.0.0
201
+ option(:database).allow(Optionable.any(String), Optionable.any(Symbol))
202
+
203
+ # Setup validation of allowed max retry options. (Any integer)
171
204
  #
172
- # @return [ :strong, :eventual ] The session's consistency.
205
+ # @since 2.0.0
206
+ option(:max_retries).allow(Optionable.any(Integer))
207
+
208
+ # Setup validation of allowed pool size options. (Any integer)
173
209
  #
174
- # @since 1.0.0
175
- def consistency
176
- options[:consistency]
177
- end
210
+ # @since 2.0.0
211
+ option(:pool_size).allow(Optionable.any(Integer))
212
+
213
+ # Setup validation of allowed retry interval options. (Any numeric)
214
+ #
215
+ # @since 2.0.0
216
+ option(:retry_interval).allow(Optionable.any(Numeric))
217
+
218
+ # Setup validation of allowed reap interval options. (Any numeric)
219
+ #
220
+ # @since 2.0.0
221
+ option(:reap_interval).allow(Optionable.any(Numeric))
222
+
223
+ # Setup validation of allowed ssl options. (Any boolean)
224
+ #
225
+ # @since 2.0.0
226
+ option(:ssl).allow(true, false)
227
+
228
+ # Setup validation of allowed timeout options. (Any numeric)
229
+ #
230
+ # @since 2.0.0
231
+ option(:timeout).allow(Optionable.any(Numeric))
178
232
 
179
233
  # Initialize a new database session.
180
234
  #
181
235
  # @example Initialize a new session.
182
236
  # Session.new([ "localhost:27017" ])
183
237
  #
184
- # @param [ Array ] seeds an of host:port pairs
185
- # @param [ Hash ] options
186
- #
187
- # @option options [ Boolean ] :safe (false) Ensure writes are persisted.
188
- # @option options [ Hash ] :safe Ensure writes are persisted with the
189
- # specified safety level e.g., "fsync: true", or "w: 2, wtimeout: 5".
190
- # @option options [ Symbol, String ] :database The database to use.
191
- # @option options [ :strong, :eventual ] :consistency (:eventual).
192
- # @option options [ Boolean ] :ssl Connect using SSL.
193
- # @option options [ Integer ] :max_retries The maximum number of attempts
194
- # to retry an operation. (30)
195
- # @option options [ Integer ] :retry_interval The time in seconds to retry
196
- # connections to a secondary or primary after a failure. (1)
197
- # @option options [ Integer ] :timeout The time in seconds to wait for an
198
- # operation to timeout. (5)
238
+ # @param [ Array ] seeds An array of host:port pairs.
239
+ # @param [ Hash ] options The options for the session.
240
+ #
241
+ # @see Above options validations for allowed values in the options hash.
199
242
  #
200
243
  # @since 1.0.0
201
244
  def initialize(seeds, options = {})
202
- @cluster = Cluster.new(seeds, options)
203
- @context = Context.new(self)
245
+ validate_strict(options)
204
246
  @options = options
205
- @options[:consistency] ||= :eventual
247
+ @cluster = Cluster.new(seeds, options)
206
248
  end
207
249
 
208
250
  # Create a new session with +options+ and use new socket connections.
209
251
  #
210
252
  # @example Change safe mode
211
- # session.with(safe: { w: 2 })[:people].insert(name: "Joe")
253
+ # session.with(write: { w: 2 })[:people].insert(name: "Joe")
212
254
  #
213
255
  # @example Change safe mode with block
214
- # session.with(safe: { w: 2 }) do |session|
256
+ # session.with(write: { w: 2 }) do |session|
215
257
  # session[:people].insert(name: "Joe")
216
258
  # end
217
259
  #
@@ -247,29 +289,17 @@ module Moped
247
289
  end
248
290
  end
249
291
 
250
- # Is the session operating in safe mode?
251
- #
252
- # @example Is the session operating in safe mode?
253
- # session.safe?
254
- #
255
- # @return [ true, false ] Whether the current session requires safe
256
- # operations.
257
- #
258
- # @since 1.0.0
259
- def safe?
260
- !!safety
261
- end
262
-
263
- # Get the safety level for the session.
292
+ # Get the read preference for the session. Will default to primary if none
293
+ # was provided.
264
294
  #
265
- # @example Get the safety level.
266
- # session.safety
295
+ # @example Get the session's read preference.
296
+ # session.read_preference
267
297
  #
268
- # @return [ Boolean, Hash ] The safety level for this session.
298
+ # @return [ Object ] The read preference.
269
299
  #
270
- # @since 1.0.0
271
- def safety
272
- options[:safe].__safe_options__
300
+ # @since 2.0.0
301
+ def read_preference
302
+ @read_preference ||= ReadPreference.get(options[:read] || :primary)
273
303
  end
274
304
 
275
305
  # Switch the session's current database.
@@ -289,10 +319,10 @@ module Moped
289
319
  # Create a new session with +options+ reusing existing connections.
290
320
  #
291
321
  # @example Change safe mode
292
- # session.with(safe: { w: 2 })[:people].insert(name: "Joe")
322
+ # session.with(write: { w: 2 })[:people].insert(name: "Joe")
293
323
  #
294
324
  # @example Change safe mode with block
295
- # session.with(safe: { w: 2 }) do |session|
325
+ # session.with(write: { w: 2 }) do |session|
296
326
  # session[:people].insert(name: "Joe")
297
327
  # end
298
328
  #
@@ -327,6 +357,19 @@ module Moped
327
357
  end
328
358
  end
329
359
 
360
+ # Get the write concern for the session. Will default to propagate if none
361
+ # was provided.
362
+ #
363
+ # @example Get the session's write concern.
364
+ # session.write_concern
365
+ #
366
+ # @return [ Object ] The write concern.
367
+ #
368
+ # @since 2.0.0
369
+ def write_concern
370
+ @write_concern ||= WriteConcern.get(options[:write] || { w: 1 })
371
+ end
372
+
330
373
  class << self
331
374
 
332
375
  # Create a new session from a URI.
@@ -340,7 +383,7 @@ module Moped
340
383
  #
341
384
  # @since 3.0.0
342
385
  def connect(uri)
343
- uri = MongoUri.new(uri)
386
+ uri = Uri.new(uri)
344
387
  session = new(*uri.moped_arguments)
345
388
  session.login(uri.username, uri.password) if uri.auth_provided?
346
389
  session
@@ -349,8 +392,18 @@ module Moped
349
392
 
350
393
  private
351
394
 
395
+ # Get the database that the session is currently using.
396
+ #
397
+ # @api private
398
+ #
399
+ # @example Get the current database.
400
+ # session.current_database
401
+ #
402
+ # @return [ Database ] The current database or nil.
403
+ #
404
+ # @since 2.0.0
352
405
  def current_database
353
- return @current_database if defined?(@current_database)
406
+ return @current_database if @current_database
354
407
  if database = options[:database]
355
408
  set_current_database(database)
356
409
  else
@@ -359,15 +412,14 @@ module Moped
359
412
  end
360
413
 
361
414
  def current_database_name
362
- defined?(@current_database) ? current_database.name : :none
415
+ @current_database ? current_database.name : :none
363
416
  end
364
417
 
365
418
  def initialize_copy(_)
366
- @context = Context.new(self)
367
419
  @options = @options.dup
368
- if defined?(@current_database)
369
- remove_instance_variable(:@current_database)
370
- end
420
+ @read_preference = nil
421
+ @write_concern = nil
422
+ @current_database = nil
371
423
  end
372
424
 
373
425
  def set_current_database(database)