mongo 2.0.4 → 2.0.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (54) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/lib/mongo/address.rb +1 -1
  5. data/lib/mongo/address/ipv4.rb +8 -4
  6. data/lib/mongo/address/ipv6.rb +8 -4
  7. data/lib/mongo/address/unix.rb +2 -2
  8. data/lib/mongo/auth/user/view.rb +5 -1
  9. data/lib/mongo/bulk_write/bulk_writable.rb +5 -0
  10. data/lib/mongo/bulk_write/deletable.rb +0 -4
  11. data/lib/mongo/bulk_write/insertable.rb +0 -4
  12. data/lib/mongo/client.rb +30 -2
  13. data/lib/mongo/collection/view/aggregation.rb +17 -4
  14. data/lib/mongo/collection/view/map_reduce.rb +19 -2
  15. data/lib/mongo/database.rb +12 -0
  16. data/lib/mongo/database/view.rb +12 -0
  17. data/lib/mongo/grid/fs.rb +5 -5
  18. data/lib/mongo/loggable.rb +5 -3
  19. data/lib/mongo/logger.rb +21 -5
  20. data/lib/mongo/operation/aggregate.rb +18 -11
  21. data/lib/mongo/operation/aggregate/result.rb +16 -1
  22. data/lib/mongo/operation/map_reduce.rb +7 -9
  23. data/lib/mongo/operation/read/query.rb +1 -1
  24. data/lib/mongo/operation/read_preferrable.rb +11 -5
  25. data/lib/mongo/operation/result.rb +5 -1
  26. data/lib/mongo/operation/write.rb +1 -0
  27. data/lib/mongo/operation/write/command.rb +1 -0
  28. data/lib/mongo/operation/write/command/update_user.rb +43 -0
  29. data/lib/mongo/operation/write/update_user.rb +75 -0
  30. data/lib/mongo/protocol/reply.rb +12 -0
  31. data/lib/mongo/server/connection_pool/queue.rb +3 -3
  32. data/lib/mongo/socket.rb +22 -11
  33. data/lib/mongo/socket/ssl.rb +6 -3
  34. data/lib/mongo/version.rb +1 -1
  35. data/spec/mongo/auth/user/view_spec.rb +42 -0
  36. data/spec/mongo/client_spec.rb +19 -0
  37. data/spec/mongo/cluster_spec.rb +2 -1
  38. data/spec/mongo/collection/view/aggregation_spec.rb +34 -1
  39. data/spec/mongo/collection/view/map_reduce_spec.rb +92 -0
  40. data/spec/mongo/collection/view_spec.rb +14 -11
  41. data/spec/mongo/collection_spec.rb +13 -0
  42. data/spec/mongo/database_spec.rb +29 -0
  43. data/spec/mongo/grid/fs_spec.rb +32 -1
  44. data/spec/mongo/loggable_spec.rb +2 -1
  45. data/spec/mongo/operation/read/query_spec.rb +19 -0
  46. data/spec/mongo/operation/read_preferrable_spec.rb +192 -0
  47. data/spec/mongo/operation/write/update_user_spec.rb +46 -0
  48. data/spec/mongo/server/connection_pool/queue_spec.rb +4 -0
  49. data/spec/mongo/socket/ssl_spec.rb +21 -1
  50. data/spec/spec_helper.rb +4 -0
  51. data/spec/support/authorization.rb +6 -4
  52. data/spec/support/shared/operation.rb +12 -0
  53. metadata +9 -3
  54. metadata.gz.sig +0 -0
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: e38363c98850f8cb9f7ef56552faf0b6bbaf88e6
4
- data.tar.gz: 9bb3295506cf0fdd420a7232283982145824cb11
3
+ metadata.gz: 009aca6194505e854c2e8ce72b50826c76b81942
4
+ data.tar.gz: ec9fa507bafe9c3f79ce430bee77bee9fa6452c3
5
5
  SHA512:
6
- metadata.gz: 391cb75664da5c1d1f24a8b61b59703b2767c60c221c601342bf2597096af1a828b1eaec2402e91e5e512e251f64534a31dcc73103062cc111f6247137953edf
7
- data.tar.gz: fe3b98b0be277225dbe52ca0a39a8bc3e31e80eff077041bf87d7327d9adfba697a8ed6b8333637dd5c6b887b7599b893b15ebfbf347af90cfdcae97582682c1
6
+ metadata.gz: ac666b6d3593018bf29f22a212bcf36a1b0dff88e9aee3e439c3f599bff14c90b8e2507355b10cc40e4426a7135313fa161d78fdc853ac4c094acfa9122d2c2c
7
+ data.tar.gz: 0ff89ae3bc0661a5a39e067a0c96d7a044b291333f314dd6dbd89e8bb7c6d2f4f95ba894785d784acc8126f66896b0505900d56b39c77c5e1a4ac66f8f43f0ca
Binary file
data.tar.gz.sig CHANGED
Binary file
@@ -148,7 +148,7 @@ module Mongo
148
148
  error = nil
149
149
  ::Socket.getaddrinfo(host, nil, family, ::Socket::SOCK_STREAM).detect do |info|
150
150
  begin
151
- return FAMILY_MAP[info[4]].new(info[3], port).tap do |res|
151
+ return FAMILY_MAP[info[4]].new(info[3], port, host).tap do |res|
152
152
  res.socket(timeout, ssl_options).connect!
153
153
  end
154
154
  rescue IOError, SystemCallError => e
@@ -21,9 +21,12 @@ module Mongo
21
21
  # @since 2.0.0
22
22
  class IPv4
23
23
 
24
- # @return [ String ] host The original host name.
24
+ # @return [ String ] host The host.
25
25
  attr_reader :host
26
26
 
27
+ # @return [ String ] host_name The original host name.
28
+ attr_reader :host_name
29
+
27
30
  # @return [ Integer ] port The port.
28
31
  attr_reader :port
29
32
 
@@ -52,15 +55,16 @@ module Mongo
52
55
  # Initialize the IPv4 resolver.
53
56
  #
54
57
  # @example Initialize the resolver.
55
- # IPv4.new("127.0.0.1", 27017, "127.0.0.1:28011")
58
+ # IPv4.new("127.0.0.1", 27017, 'localhost')
56
59
  #
57
60
  # @param [ String ] host The host.
58
61
  # @param [ Integer ] port The port.
59
62
  #
60
63
  # @since 2.0.0
61
- def initialize(host, port)
64
+ def initialize(host, port, host_name=nil)
62
65
  @host = host
63
66
  @port = port
67
+ @host_name = host_name
64
68
  end
65
69
 
66
70
  # Get a socket for the provided address type, given the options.
@@ -76,7 +80,7 @@ module Mongo
76
80
  # @since 2.0.0
77
81
  def socket(timeout, ssl_options = {})
78
82
  unless ssl_options.empty?
79
- Socket::SSL.new(host, port, timeout, Socket::PF_INET, ssl_options)
83
+ Socket::SSL.new(host, port, host_name, timeout, Socket::PF_INET, ssl_options)
80
84
  else
81
85
  Socket::TCP.new(host, port, timeout, Socket::PF_INET)
82
86
  end
@@ -21,9 +21,12 @@ module Mongo
21
21
  # @since 2.0.0
22
22
  class IPv6
23
23
 
24
- # @return [ String ] host The original host name.
24
+ # @return [ String ] host The host.
25
25
  attr_reader :host
26
26
 
27
+ # @return [ String ] host_name The original host name.
28
+ attr_reader :host_name
29
+
27
30
  # @return [ Integer ] port The port.
28
31
  attr_reader :port
29
32
 
@@ -52,15 +55,16 @@ module Mongo
52
55
  # Initialize the IPv6 resolver.
53
56
  #
54
57
  # @example Initialize the resolver.
55
- # IPv6.new("::1", 28011, "[::1]:28011")
58
+ # IPv6.new("::1", 28011, 'localhost')
56
59
  #
57
60
  # @param [ String ] host The host.
58
61
  # @param [ Integer ] port The port.
59
62
  #
60
63
  # @since 2.0.0
61
- def initialize(host, port)
64
+ def initialize(host, port, host_name=nil)
62
65
  @host = host
63
66
  @port = port
67
+ @host_name = host_name
64
68
  end
65
69
 
66
70
  # Get a socket for the provided address type, given the options.
@@ -76,7 +80,7 @@ module Mongo
76
80
  # @since 2.0.0
77
81
  def socket(timeout, ssl_options = {})
78
82
  unless ssl_options.empty?
79
- Socket::SSL.new(host, port, timeout, Socket::PF_INET6, ssl_options)
83
+ Socket::SSL.new(host, port, host_name, timeout, Socket::PF_INET6, ssl_options)
80
84
  else
81
85
  Socket::TCP.new(host, port, timeout, Socket::PF_INET6)
82
86
  end
@@ -20,7 +20,7 @@ module Mongo
20
20
  # @since 2.0.0
21
21
  class Unix
22
22
 
23
- # @return [ String ] host The original host name.
23
+ # @return [ String ] host The host.
24
24
  attr_reader :host
25
25
 
26
26
  # @return [ nil ] port Will always be nil.
@@ -53,7 +53,7 @@ module Mongo
53
53
  # @param [ String ] host The host.
54
54
  #
55
55
  # @since 2.0.0
56
- def initialize(host)
56
+ def initialize(host, port=nil, host_name=nil)
57
57
  @host = host
58
58
  end
59
59
 
@@ -88,7 +88,11 @@ module Mongo
88
88
  #
89
89
  # @since 2.0.0
90
90
  def update(user_or_name, options = {})
91
-
91
+ user = generate(user_or_name, options)
92
+ Operation::Write::UpdateUser.new(
93
+ user: user,
94
+ db_name: database.name
95
+ ).execute(next_primary.context)
92
96
  end
93
97
 
94
98
  private
@@ -85,6 +85,11 @@ module Mongo
85
85
 
86
86
  private
87
87
 
88
+ def valid_doc?(doc)
89
+ doc.respond_to?(:keys) ||
90
+ doc.respond_to?(:document)
91
+ end
92
+
88
93
  def write_concern
89
94
  @write_concern ||= WriteConcern.get(@options[:write_concern]) ||
90
95
  @collection.write_concern
@@ -22,10 +22,6 @@ module Mongo
22
22
 
23
23
  private
24
24
 
25
- def valid_doc?(doc)
26
- doc.respond_to?(:keys)
27
- end
28
-
29
25
  def validate_delete_op!(type, d)
30
26
  raise Error::InvalidBulkOperation.new(type, d) unless valid_doc?(d)
31
27
  end
@@ -22,10 +22,6 @@ module Mongo
22
22
 
23
23
  private
24
24
 
25
- def valid_doc?(doc)
26
- doc.respond_to?(:keys)
27
- end
28
-
29
25
  def validate_insert_ops!(type, inserts)
30
26
  if inserts.empty?
31
27
  raise Error::InvalidBulkOperation.new(type, inserts)
@@ -111,8 +111,10 @@ module Mongo
111
111
  # seconds, in the connection pool for a connection to be checked in.
112
112
  # @option options [ Float ] :connect_timeout The timeout, in seconds, to
113
113
  # attempt a connection.
114
- # @option options [ Symbol ] :read The read preference options. :mode can
115
- # be one of :secondary, :secondary_preferred, :primary,
114
+ # @option options [ Hash ] :read The read preference options. They consist of a
115
+ # mode specified as a symbol, an array of hashes known as tag_sets,
116
+ # and two timing options: local_threshold and server_selection_timeout.
117
+ # :mode can be one of :secondary, :secondary_preferred, :primary,
116
118
  # :primary_preferred, :nearest.
117
119
  # @option options [ Array<Hash, String> ] :roles The list of roles for the
118
120
  # user.
@@ -221,6 +223,32 @@ module Mongo
221
223
  @write_concern ||= WriteConcern.get(options[:write])
222
224
  end
223
225
 
226
+ # Get the names of all databases.
227
+ #
228
+ # @example Get the database names.
229
+ # client.database_names
230
+ #
231
+ # @return [ Array<String> ] The names of the databases.
232
+ #
233
+ # @since 2.0.5
234
+ def database_names
235
+ list_databases.collect{ |info| info['name'] }
236
+ end
237
+
238
+ # Get info for each database.
239
+ #
240
+ # @example Get the info for each database.
241
+ # client.list_databases
242
+ #
243
+ # @return [ Array<Hash> ] The info for each database.
244
+ #
245
+ # @since 2.0.5
246
+ def list_databases
247
+ use(Database::ADMIN).command(
248
+ listDatabases: 1
249
+ ).first['databases']
250
+ end
251
+
224
252
  private
225
253
 
226
254
  def create_from_addresses(addresses, opts = {})
@@ -69,16 +69,29 @@ module Mongo
69
69
  @options = options.dup
70
70
  end
71
71
 
72
+ # Get the explain plan for the aggregation.
73
+ #
74
+ # @example Get the explain plan for the aggregation.
75
+ # aggregation.explain
76
+ #
77
+ # @return [ Hash ] The explain plan.
78
+ #
79
+ # @since 2.0.0
80
+ def explain
81
+ self.class.new(view, pipeline, options.merge(explain_options)).first
82
+ end
83
+
72
84
  private
73
85
 
74
86
  def aggregate_spec
75
- { :selector => {
87
+ { :db_name => database.name,
88
+ :read => read,
89
+ :selector => {
76
90
  :aggregate => collection.name,
77
91
  :pipeline => pipeline,
78
92
  :cursor => view.batch_size ? { :batchSize => view.batch_size } : {}
79
- }.merge!(options),
80
- :db_name => database.name,
81
- :options => view.options }
93
+ }.merge!(options)
94
+ }
82
95
  end
83
96
 
84
97
  def explain_options
@@ -120,7 +120,7 @@ module Mongo
120
120
  #
121
121
  # @param [ Hash ] object The scope object.
122
122
  #
123
- # @return [ MapReduce, Hash ] The new MapReduce operation or thevalue
123
+ # @return [ MapReduce, Hash ] The new MapReduce operation or the value
124
124
  # of the scope.
125
125
  #
126
126
  # @since 2.0.0
@@ -128,15 +128,32 @@ module Mongo
128
128
  configure(:scope, object)
129
129
  end
130
130
 
131
+ # Whether to include the timing information in the result.
132
+ #
133
+ # @example Set the verbose value.
134
+ # map_reduce.verbose(false)
135
+ #
136
+ # @param [ true, false ] value Whether to include timing information
137
+ # in the result.
138
+ #
139
+ # @return [ MapReduce, Hash ] The new MapReduce operation or the value
140
+ # of the verbose option.
141
+ #
142
+ # @since 2.0.5
143
+ def verbose(value = nil)
144
+ configure(:verbose, value)
145
+ end
146
+
131
147
  private
132
148
 
133
149
  def inline?
134
- out.nil? || out == { inline: 1 }
150
+ out.nil? || out == { inline: 1 } || out == { 'inline' => 1 }
135
151
  end
136
152
 
137
153
  def map_reduce_spec
138
154
  {
139
155
  :db_name => database.name,
156
+ :read => read,
140
157
  :selector => {
141
158
  :mapreduce => collection.name,
142
159
  :map => map,
@@ -102,6 +102,18 @@ module Mongo
102
102
  View.new(self).collection_names(options)
103
103
  end
104
104
 
105
+ # Get info on all the collections in the database.
106
+ #
107
+ # @example Get info on each collection.
108
+ # database.list_collections
109
+ #
110
+ # @return [ Array<Hash> ] Info for each collection in the database.
111
+ #
112
+ # @since 2.0.5
113
+ def list_collections
114
+ View.new(self).list_collections
115
+ end
116
+
105
117
  # Get all the collections that belong to this database.
106
118
  #
107
119
  # @example Get all the collections.
@@ -57,6 +57,18 @@ module Mongo
57
57
  end
58
58
  end
59
59
 
60
+ # Get info on all the collections in the database.
61
+ #
62
+ # @example Get info on each collection.
63
+ # database.list_collections
64
+ #
65
+ # @return [ Array<Hash> ] Info for each collection in the database.
66
+ #
67
+ # @since 2.0.5
68
+ def list_collections
69
+ collections_info(next_primary)
70
+ end
71
+
60
72
  # Create the new database view.
61
73
  #
62
74
  # @example Create the new database view.
@@ -75,12 +75,12 @@ module Mongo
75
75
  # @since 2.0.0
76
76
  def insert_one(file)
77
77
  files_collection.insert_one(file.metadata)
78
- result = chunks_collection.insert_many(file.chunks)
79
- if write_concern.get_last_error
80
- validate_md5!(file)
81
- else
82
- result
78
+ inserts = file.chunks.reduce([]) do |ops, chunk|
79
+ ops << { :insert_one => chunk }
83
80
  end
81
+ result = chunks_collection.bulk_write(inserts, ordered: true)
82
+ validate_md5!(file) if write_concern.get_last_error
83
+ file.id
84
84
  end
85
85
 
86
86
  # Create the GridFS.
@@ -45,9 +45,11 @@ module Mongo
45
45
  rescue Exception => e
46
46
  raise e
47
47
  ensure
48
- runtime = ("%.4fms" % (1000 * (Time.now.to_f - started.to_f)))
49
- operations.each do |operation|
50
- Logger.send(level, prefix, log_inspect(operation), runtime)
48
+ if Logger.allow?(level)
49
+ runtime = format("%.4fms", (Time.now.to_f - started.to_f) * 1000.0)
50
+ operations.each do |operation|
51
+ Logger.log(level, prefix, log_inspect(operation), runtime)
52
+ end
51
53
  end
52
54
  end
53
55
  end
@@ -34,7 +34,7 @@ module Mongo
34
34
  #
35
35
  # @since 2.0.0
36
36
  def debug(prefix, message, runtime)
37
- logger.debug("#{prefix} | #{message} | runtime: #{runtime}")
37
+ self.log(:debug, prefix, message, runtime)
38
38
  end
39
39
 
40
40
  # Log a error level message.
@@ -48,7 +48,7 @@ module Mongo
48
48
  #
49
49
  # @since 2.0.0
50
50
  def error(prefix, message, runtime)
51
- logger.error("#{prefix} | #{message} | runtime: #{runtime}")
51
+ self.log(:error, prefix, message, runtime)
52
52
  end
53
53
 
54
54
  # Log a fatal level message.
@@ -62,7 +62,7 @@ module Mongo
62
62
  #
63
63
  # @since 2.0.0
64
64
  def fatal(prefix, message, runtime)
65
- logger.fatal("#{prefix} | #{message} | runtime: #{runtime}")
65
+ self.log(:fatal, prefix, message, runtime)
66
66
  end
67
67
 
68
68
  # Log a info level message.
@@ -76,7 +76,7 @@ module Mongo
76
76
  #
77
77
  # @since 2.0.0
78
78
  def info(prefix, message, runtime)
79
- logger.info("#{prefix} | #{message} | runtime: #{runtime}")
79
+ self.log(:info, prefix, message, runtime)
80
80
  end
81
81
 
82
82
  # Log a warn level message.
@@ -90,7 +90,7 @@ module Mongo
90
90
  #
91
91
  # @since 2.0.0
92
92
  def warn(prefix, message, runtime)
93
- logger.warn("#{prefix} | #{message} | runtime: #{runtime}")
93
+ self.log(:warn, prefix, message, runtime)
94
94
  end
95
95
 
96
96
  # Get the wrapped logger. If none was set will return a default debug
@@ -120,6 +120,22 @@ module Mongo
120
120
  @logger = other
121
121
  end
122
122
 
123
+ def log(level, prefix, message, runtime)
124
+ logger.send(level, format("%s | %s | runtime: %s".freeze, prefix, message, runtime))
125
+ end
126
+
127
+ def allow?(level)
128
+ logger.send(:"#{level}?")
129
+ end
130
+
131
+ def level
132
+ logger.level
133
+ end
134
+
135
+ def level=(level)
136
+ logger.level = level
137
+ end
138
+
123
139
  private
124
140
 
125
141
  def default_logger
@@ -43,6 +43,7 @@ module Mongo
43
43
  include Executable
44
44
  include Specifiable
45
45
  include Limited
46
+ include ReadPreferrable
46
47
 
47
48
  # The need primary error message.
48
49
  #
@@ -62,7 +63,7 @@ module Mongo
62
63
  #
63
64
  # @since 2.0.0
64
65
  def execute(context)
65
- unless context.standalone? || context.mongos? || context.primary? || secondary_ok?
66
+ unless valid_context?(context)
66
67
  raise Error::NeedPrimaryServer.new(ERROR_MESSAGE)
67
68
  end
68
69
  execute_message(context)
@@ -76,24 +77,30 @@ module Mongo
76
77
  end
77
78
  end
78
79
 
79
- # Whether this operation can be executed on a replica set secondary server.
80
- # The aggregate operation may not be executed on a secondary if the user has specified
81
- # an output collection to which the results will be written.
82
- #
83
- # @return [ true, false ] Whether the operation can be executed on a secondary.
84
- #
85
- # @since 2.0.0
80
+ def valid_context?(context)
81
+ context.standalone? || context.mongos? || context.primary? || secondary_ok?
82
+ end
83
+
86
84
  def secondary_ok?
87
85
  selector[:pipeline].none? { |op| op.key?('$out') || op.key?(:$out) }
88
86
  end
89
87
 
90
- def filter(context)
88
+ def query_coll
89
+ Database::COMMAND
90
+ end
91
+
92
+ def filter_selector(context)
91
93
  return selector if context.features.write_command_enabled?
92
94
  selector.reject{ |option, value| option.to_s == 'cursor' }
93
95
  end
94
96
 
95
- def message(context)
96
- Protocol::Query.new(db_name, Database::COMMAND, filter(context), options)
97
+ def update_selector(context)
98
+ if context.mongos? && read_pref = read.to_mongos
99
+ sel = selector[:$query] ? filter_selector(context) : { :$query => filter_selector(context) }
100
+ sel.merge(:$readPreference => read_pref)
101
+ else
102
+ filter_selector(context)
103
+ end
97
104
  end
98
105
  end
99
106
  end