mongo 2.2.1 → 2.2.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (39) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +1 -0
  4. data/lib/mongo/bson.rb +1 -1
  5. data/lib/mongo/cluster/topology/replica_set.rb +21 -4
  6. data/lib/mongo/collection/view/readable.rb +0 -1
  7. data/lib/mongo/error/operation_failure.rb +3 -1
  8. data/lib/mongo/grid/file.rb +14 -11
  9. data/lib/mongo/grid/file/chunk.rb +12 -10
  10. data/lib/mongo/grid/fs_bucket.rb +2 -2
  11. data/lib/mongo/grid/stream/read.rb +1 -1
  12. data/lib/mongo/grid/stream/write.rb +5 -5
  13. data/lib/mongo/options/mapper.rb +17 -0
  14. data/lib/mongo/protocol/message.rb +1 -1
  15. data/lib/mongo/server/connection.rb +3 -25
  16. data/lib/mongo/server/description.rb +19 -2
  17. data/lib/mongo/version.rb +1 -1
  18. data/lib/mongo/write_concern/normalizable.rb +2 -1
  19. data/spec/mongo/client_spec.rb +1 -1
  20. data/spec/mongo/collection/view/readable_spec.rb +18 -0
  21. data/spec/mongo/grid/file/chunk_spec.rb +1 -0
  22. data/spec/mongo/grid/file_spec.rb +25 -6
  23. data/spec/mongo/grid/stream/write_spec.rb +11 -0
  24. data/spec/mongo/protocol/reply_spec.rb +13 -0
  25. data/spec/mongo/server/connection_spec.rb +4 -4
  26. data/spec/mongo/write_concern_spec.rb +15 -0
  27. data/spec/support/command_monitoring.rb +3 -0
  28. data/spec/support/sdam/rs/equal_electionids.yml +4 -0
  29. data/spec/support/sdam/rs/new_primary_new_electionid.yml +7 -1
  30. data/spec/support/sdam/rs/new_primary_new_setversion.yml +101 -0
  31. data/spec/support/sdam/rs/null_election_id.yml +8 -1
  32. data/spec/support/sdam/rs/primary_disconnect_electionid.yml +37 -1
  33. data/spec/support/sdam/rs/primary_disconnect_setversion.yml +160 -0
  34. data/spec/support/sdam/rs/set_version_without_electionid.yml +69 -0
  35. data/spec/support/sdam/rs/setversion_without_electionid.yml +69 -0
  36. data/spec/support/sdam/rs/use_setversion_without_electionid.yml +99 -0
  37. metadata +36 -5
  38. metadata.gz.sig +1 -0
  39. data/lib/csasl/csasl.bundle +0 -0
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 70bb36aedc302fa28a3103c1216e865448733b54
4
- data.tar.gz: 05f39ba3e498bd4763f89ca4ac7b30d9d5b3537f
3
+ metadata.gz: 72df9675f13de7a6111464ef0089ba64b4ef11af
4
+ data.tar.gz: 20832950dd436fb031938d2e164cca2c7fe5d84c
5
5
  SHA512:
6
- metadata.gz: 704bcf79dd037eeb329fd5e9120d9ead72b80f8bf4897e9260e2b624afad5c280feb0300228cee83b8ff639f97ef288e9dcf4ea7d6aa86b519e2e6f15853e688
7
- data.tar.gz: c25ecaaee43f90ee59c501712aa8632802a31136deebc90cebaa6bb31ba419be5ba44ad9ad5f5f1c721bf36c722c6828e65bf340fdf34b41f967a91f0414e7bd
6
+ metadata.gz: eaaf003581ddec08e424a7a8168917b4a971514029527229ffe0e1a5746715be52caf0eb8e1f3ef4af29e35d744b23240282fecfa157280f4e31cb4f8c03bfbf
7
+ data.tar.gz: 32dd69254433179769be7b7d030e230da1b499ce59da53ab1535b1d736cca6dd2a3bb8d1516323abdf3f8dbb7d2285356ef011c708f8a460cc2ffa1e4e88f015
Binary file
@@ -0,0 +1 @@
1
+ ���Y;ht����S���~r�٘-��ZK���cu�̸x����=��\�w�JG��%@y�U�3x;� d�:IR"�^�i�\���<^;O�Y����H�,�;_1eH�����6���(�>�/�`zRІ|@N �&����b�lz�8r��jy�ѓ��C����i,JY(^Q�a�ydQ���"…_�k�94�J#*5���hi�F���'�����`~+�85�>q���Nl��|[]/��8&�no���v
@@ -23,7 +23,7 @@ class Symbol
23
23
  # @example Get the bson type.
24
24
  # :test.bson_type
25
25
  #
26
- # @return [ String ] The charater 14.
26
+ # @return [ String ] The character 14.
27
27
  #
28
28
  # @since 2.2.1
29
29
  def bson_type
@@ -68,6 +68,7 @@ module Mongo
68
68
  end
69
69
  end
70
70
  update_max_election_id(description)
71
+ update_max_set_version(description)
71
72
  end
72
73
  else
73
74
  log_warn(
@@ -88,7 +89,8 @@ module Mongo
88
89
  # @since 2.0.0
89
90
  def initialize(options, seeds = [])
90
91
  @options = options
91
- @max_election_id = 0
92
+ @max_election_id = nil
93
+ @max_set_version = nil
92
94
  end
93
95
 
94
96
  # A replica set topology is a replica set.
@@ -222,14 +224,29 @@ module Mongo
222
224
  private
223
225
 
224
226
  def update_max_election_id(description)
225
- if description.election_id && description.election_id > @max_election_id
227
+ if description.election_id &&
228
+ (@max_election_id.nil? ||
229
+ description.election_id > @max_election_id)
226
230
  @max_election_id = description.election_id
227
231
  end
228
232
  end
229
233
 
234
+ def update_max_set_version(description)
235
+ if description.set_version &&
236
+ (@max_set_version.nil? ||
237
+ description.set_version > @max_set_version)
238
+ @max_set_version = description.set_version
239
+ end
240
+ end
241
+
230
242
  def detect_stale_primary!(description)
231
- if description.election_id && description.election_id < @max_election_id
232
- description.unknown!
243
+ if description.election_id && description.set_version
244
+ if @max_set_version && @max_election_id &&
245
+ (description.set_version < @max_set_version ||
246
+ (description.set_version == @max_set_version &&
247
+ description.election_id < @max_election_id))
248
+ description.unknown!
249
+ end
233
250
  end
234
251
  end
235
252
 
@@ -120,7 +120,6 @@ module Mongo
120
120
  # @option options :limit [ Integer ] Max number of docs to return.
121
121
  # @option options :max_time_ms [ Integer ] The maximum amount of time to allow the
122
122
  # command to run.
123
- # @option options :read [ Hash ] The read preference for this command.
124
123
  #
125
124
  # @return [ Integer ] The document count.
126
125
  #
@@ -37,7 +37,9 @@ module Mongo
37
37
  'error querying',
38
38
  'could not get last error',
39
39
  'connection attempt failed',
40
- 'interrupted at shutdown'
40
+ 'interrupted at shutdown',
41
+ 'unknown replica set',
42
+ 'dbclient error communicating with server'
41
43
  ].freeze
42
44
 
43
45
  # Can the operation that caused the error be retried?
@@ -30,9 +30,6 @@ module Mongo
30
30
  # @return [ Array<Chunk> ] chunks The file chunks.
31
31
  attr_reader :chunks
32
32
 
33
- # @return [ IO ] data The raw data for the file.
34
- attr_reader :data
35
-
36
33
  # @return [ File::Info ] info The file information.
37
34
  attr_reader :info
38
35
 
@@ -48,7 +45,7 @@ module Mongo
48
45
  # @since 2.0.0
49
46
  def ==(other)
50
47
  return false unless other.is_a?(File)
51
- chunks == other.chunks && data == other.data && info == other.info
48
+ chunks == other.chunks && info == other.info
52
49
  end
53
50
 
54
51
  # Initialize the file.
@@ -56,8 +53,8 @@ module Mongo
56
53
  # @example Create the file.
57
54
  # Grid::File.new(data, :filename => 'test.txt')
58
55
  #
59
- # @param [ IO, Array<BSON::Document> ] data The file or IO object or
60
- # chunks.
56
+ # @param [ IO, String, Array<BSON::Document> ] data The file object, file
57
+ # contents or chunks.
61
58
  # @param [ BSON::Document, Hash ] options The info options.
62
59
  #
63
60
  # @option options [ String ] :filename Required name of the file.
@@ -71,10 +68,19 @@ module Mongo
71
68
  #
72
69
  # @since 2.0.0
73
70
  def initialize(data, options = {})
74
- @info = Info.new(options.merge(:length => data.length))
71
+ @info = Info.new(options.merge(:length => data.size))
75
72
  initialize_chunks!(data)
76
73
  end
77
74
 
75
+ # Joins chunks into a string.
76
+ #
77
+ # @return [ String ] The raw data for the file.
78
+ #
79
+ # @since 2.0.0
80
+ def data
81
+ @data ||= Chunk.assemble(chunks)
82
+ end
83
+
78
84
  # Gets a pretty inspection of the file.
79
85
  #
80
86
  # @example Get the file inspection.
@@ -96,12 +102,9 @@ module Mongo
96
102
  # the original data itself.
97
103
  def initialize_chunks!(value)
98
104
  if value.is_a?(Array)
99
- chks = value.map{ |doc| Chunk.new(doc) }
100
- @chunks = chks
101
- @data = Chunk.assemble(chks)
105
+ @chunks = value.map{ |doc| Chunk.new(doc) }
102
106
  else
103
107
  @chunks = Chunk.split(value, info)
104
- @data = value
105
108
  end
106
109
  end
107
110
  end
@@ -12,6 +12,8 @@
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
14
 
15
+ require 'stringio'
16
+
15
17
  module Mongo
16
18
  module Grid
17
19
  class File
@@ -159,23 +161,23 @@ module Mongo
159
161
  # @example Split the data into chunks.
160
162
  # Chunks.split(data)
161
163
  #
162
- # @param [ String ] data The raw bytes.
164
+ # @param [ String, IO ] data The raw bytes.
163
165
  # @param [ File::Info ] file_info The files collection file doc.
164
166
  #
165
167
  # @return [ Array<Chunk> ] The chunks of the data.
166
168
  #
167
169
  # @since 2.0.0
168
- def split(data, file_info, offset = 0)
169
- chunks, index, n = [], 0, offset
170
- while index < data.length
171
- bytes = data.slice(index, file_info.chunk_size)
170
+ def split(io, file_info, offset = 0)
171
+ io = StringIO.new(io) if io.is_a?(String)
172
+ parts = Enumerator.new { |y| y << io.read(file_info.chunk_size) until io.eof? }
173
+ parts.map.with_index do |bytes, n|
172
174
  file_info.md5.update(bytes)
173
- chunk = Chunk.new(:data => BSON::Binary.new(bytes), :files_id => file_info.id, :n => n)
174
- chunks.push(chunk)
175
- index += bytes.length
176
- n += 1
175
+ Chunk.new(
176
+ data: BSON::Binary.new(bytes),
177
+ files_id: file_info.id,
178
+ n: n + offset,
179
+ )
177
180
  end
178
- chunks
179
181
  end
180
182
  end
181
183
  end
@@ -359,8 +359,8 @@ module Mongo
359
359
  # chunks collection. After all the chunks have been uploaded, it creates a files collection
360
360
  # document for the filename in the files collection.
361
361
  #
362
- # @example Open a stream to which the contents of a file came be written.
363
- # fs.open_upload_stream('a-file.txt')
362
+ # @example Upload a file to the GridFS bucket.
363
+ # fs.upload_from_stream('a-file.txt')
364
364
  #
365
365
  # @param [ String ] filename The filename of the file to upload.
366
366
  # @param [ IO ] io The source io stream to upload from.
@@ -74,7 +74,7 @@ module Mongo
74
74
  view.each_with_index.reduce(0) do |length_read, (doc, index)|
75
75
  chunk = Grid::File::Chunk.new(doc)
76
76
  validate!(index, num_chunks, chunk, length_read)
77
- data = Grid::File::Chunk.assemble([ chunk ])
77
+ data = chunk.data.data
78
78
  yield data
79
79
  length_read += data.size
80
80
  end if block_given?
@@ -82,9 +82,8 @@ module Mongo
82
82
  def write(io)
83
83
  ensure_open!
84
84
  @indexes ||= ensure_indexes!
85
- data = io.read
86
- @length += data.length
87
- chunks = File::Chunk.split(data, file_info, @n)
85
+ @length += io.size
86
+ chunks = File::Chunk.split(io, file_info, @n)
88
87
  @n += chunks.size
89
88
  chunks_collection.insert_many(chunks) unless chunks.empty?
90
89
  self
@@ -157,10 +156,11 @@ module Mongo
157
156
  end
158
157
 
159
158
  def with_write_concern(collection)
160
- if collection.write_concern.options == write_concern.options
159
+ if write_concern.nil? || (collection.write_concern &&
160
+ collection.write_concern.options == write_concern.options)
161
161
  collection
162
162
  else
163
- collection.client.with(write: write_concern.options)[collection.name]
163
+ collection.with(write: write_concern.options)
164
164
  end
165
165
  end
166
166
 
@@ -81,6 +81,23 @@ module Mongo
81
81
  end
82
82
  end
83
83
 
84
+ # Coverts all the keys of the options to symbols.
85
+ #
86
+ # @example Convert all option keys to symbols.
87
+ # Mapper.transform({ 'name' => 1 })
88
+ #
89
+ # @param [ Hash ] options The options to transform.
90
+ #
91
+ # @return [ Hash ] The transformed options.
92
+ #
93
+ # @since 2.2.2
94
+ def transform_keys_to_symbols(options)
95
+ options.reduce({}) do |transformed, (key, value)|
96
+ transformed[key.to_sym] = value
97
+ transformed
98
+ end
99
+ end
100
+
84
101
  # Coverts all the symbol values to strings.
85
102
  #
86
103
  # @example Convert all option symbol values to strings.
@@ -114,7 +114,7 @@ module Mongo
114
114
 
115
115
  # Protection from potential DOS man-in-the-middle attacks. See
116
116
  # DRIVERS-276.
117
- if length > max_message_size
117
+ if length > (max_message_size || MAX_MESSAGE_SIZE)
118
118
  raise Error::MaxMessageSize.new(max_message_size)
119
119
  end
120
120
 
@@ -38,29 +38,12 @@ module Mongo
38
38
  # @since 2.1.0
39
39
  PING_BYTES = PING_MESSAGE.serialize.to_s.freeze
40
40
 
41
- # @return [ Mongo::Auth::CR, Mongo::Auth::X509, Mongo::Auth:LDAP, Mongo::Auth::SCRAM ]
42
- # authenticator The authentication strategy.
43
- attr_reader :authenticator
44
-
45
41
  def_delegators :@server,
46
42
  :features,
47
43
  :max_bson_object_size,
48
44
  :max_message_size,
49
45
  :mongos?
50
46
 
51
- # Is this connection authenticated. Will return true if authorization
52
- # details were provided and authentication passed.
53
- #
54
- # @example Is the connection authenticated?
55
- # connection.authenticated?
56
- #
57
- # @return [ true, false ] If the connection is authenticated.
58
- #
59
- # @since 2.0.0
60
- def authenticated?
61
- !!@authenticated
62
- end
63
-
64
47
  # Tell the underlying socket to establish a connection to the host.
65
48
  #
66
49
  # @example Connect to the host.
@@ -76,10 +59,7 @@ module Mongo
76
59
  unless socket
77
60
  @socket = address.socket(timeout, ssl_options)
78
61
  socket.connect!
79
- if authenticator
80
- authenticator.login(self)
81
- @authenticated = true
82
- end
62
+ authenticate!
83
63
  end
84
64
  true
85
65
  end
@@ -99,7 +79,6 @@ module Mongo
99
79
  if socket
100
80
  socket.close
101
81
  @socket = nil
102
- @authenticated = false
103
82
  end
104
83
  true
105
84
  end
@@ -151,7 +130,6 @@ module Mongo
151
130
  @ssl_options = options.reject { |k, v| !k.to_s.start_with?(SSL) }
152
131
  @socket = nil
153
132
  @pid = Process.pid
154
- setup_authentication!
155
133
  end
156
134
 
157
135
  # Ping the connection to see if the server is responding to commands.
@@ -180,11 +158,11 @@ module Mongo
180
158
  messages.last.replyable? ? read : nil
181
159
  end
182
160
 
183
- def setup_authentication!
161
+ def authenticate!
184
162
  if options[:user]
185
163
  default_mechanism = @server.features.scram_sha_1_enabled? ? :scram : :mongodb_cr
186
164
  user = Auth::User.new(Options::Redacted.new(:auth_mech => default_mechanism).merge(options))
187
- @authenticator = Auth.get(user)
165
+ Auth.get(user).login(self)
188
166
  end
189
167
  end
190
168
 
@@ -129,11 +129,16 @@ module Mongo
129
129
  # @since 2.0.0
130
130
  TAGS = 'tags'.freeze
131
131
 
132
- # Constant for reading electionID info from config.
132
+ # Constant for reading electionId info from config.
133
133
  #
134
134
  # @since 2.1.0
135
135
  ELECTION_ID = 'electionId'.freeze
136
136
 
137
+ # Constant for reading setVersion info from config.
138
+ #
139
+ # @since 2.2.2
140
+ SET_VERSION = 'setVersion'.freeze
141
+
137
142
  # Constant for reading localTime info from config.
138
143
  #
139
144
  # @since 2.1.0
@@ -142,7 +147,7 @@ module Mongo
142
147
  # Fields to exclude when comparing two descriptions.
143
148
  #
144
149
  # @since 2.0.6
145
- EXCLUDE_FOR_COMPARISON = [ LOCAL_TIME, ELECTION_ID ].freeze
150
+ EXCLUDE_FOR_COMPARISON = [ LOCAL_TIME, ELECTION_ID, SET_VERSION ].freeze
146
151
 
147
152
  # @return [ Address ] address The server's address.
148
153
  attr_reader :address
@@ -343,6 +348,18 @@ module Mongo
343
348
  config[ELECTION_ID]
344
349
  end
345
350
 
351
+ # Get the setVersion from the config.
352
+ #
353
+ # @example Get the setVersion.
354
+ # description.set_version
355
+ #
356
+ # @return [ Integer ] The set version.
357
+ #
358
+ # @since 2.2.2
359
+ def set_version
360
+ config[SET_VERSION]
361
+ end
362
+
346
363
  # Is the server a mongos?
347
364
  #
348
365
  # @example Is the server a mongos?
@@ -17,5 +17,5 @@ module Mongo
17
17
  # The current version of the driver.
18
18
  #
19
19
  # @since 2.0.0
20
- VERSION = '2.2.1'.freeze
20
+ VERSION = '2.2.2'.freeze
21
21
  end
@@ -44,7 +44,8 @@ module Mongo
44
44
  #
45
45
  # @since 2.0.0
46
46
  def initialize(options)
47
- @options = options.freeze
47
+ opts = Options::Mapper.transform_keys_to_symbols(options)
48
+ @options = Options::Mapper.transform_values_to_strings(opts).freeze
48
49
  end
49
50
  end
50
51
  end
@@ -688,7 +688,7 @@ describe Mongo::Client do
688
688
  end
689
689
 
690
690
  it 'returns a acknowledged write concern' do
691
- expect(concern.get_last_error).to eq(:getlasterror => 1, 'j' => true)
691
+ expect(concern.get_last_error).to eq(:getlasterror => 1, :j => true)
692
692
  end
693
693
  end
694
694
 
@@ -377,6 +377,17 @@ describe Mongo::Collection::View::Readable do
377
377
  expect(distinct).to be_empty
378
378
  end
379
379
  end
380
+
381
+ context 'when the field does not exist' do
382
+
383
+ let(:distinct) do
384
+ view.distinct(:doesnotexist)
385
+ end
386
+
387
+ it 'returns an empty array' do
388
+ expect(distinct).to be_empty
389
+ end
390
+ end
380
391
  end
381
392
 
382
393
  context 'when no selector is provided' do
@@ -462,6 +473,13 @@ describe Mongo::Collection::View::Readable do
462
473
  expect(view.distinct(:field, max_time_ms: 100)).to eq([ 'test' ])
463
474
  end
464
475
  end
476
+
477
+ context 'when the field does not exist' do
478
+
479
+ it 'returns an empty array' do
480
+ expect(view.distinct(:nofieldexists)).to be_empty
481
+ end
482
+ end
465
483
  end
466
484
 
467
485
  describe '#hint' do