mongo 2.2.1 → 2.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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