mongo 2.13.2 → 2.13.3

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 (40) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/lib/mongo/collection.rb +2 -0
  4. data/lib/mongo/database.rb +14 -2
  5. data/lib/mongo/grid/fs_bucket.rb +37 -37
  6. data/lib/mongo/operation/parallel_scan/command.rb +1 -2
  7. data/lib/mongo/operation/shared/read_preference_supported.rb +38 -36
  8. data/lib/mongo/operation/shared/sessions_supported.rb +3 -2
  9. data/lib/mongo/protocol/msg.rb +2 -2
  10. data/lib/mongo/protocol/query.rb +11 -11
  11. data/lib/mongo/server_selector/secondary_preferred.rb +2 -7
  12. data/lib/mongo/version.rb +1 -1
  13. data/spec/integration/sdam_error_handling_spec.rb +1 -1
  14. data/spec/integration/sdam_events_spec.rb +3 -5
  15. data/spec/integration/secondary_reads_spec.rb +102 -0
  16. data/spec/mongo/index/view_spec.rb +4 -2
  17. data/spec/mongo/operation/read_preference_legacy_spec.rb +9 -19
  18. data/spec/mongo/operation/read_preference_op_msg_spec.rb +3 -3
  19. data/spec/mongo/server/app_metadata_shared.rb +33 -7
  20. data/spec/mongo/server_selector/secondary_preferred_spec.rb +6 -6
  21. data/spec/runners/transactions/operation.rb +13 -2
  22. data/spec/shared/bin/get-mongodb-download-url +17 -0
  23. data/spec/shared/lib/mrss/cluster_config.rb +221 -0
  24. data/spec/shared/lib/mrss/constraints.rb +43 -0
  25. data/spec/shared/lib/mrss/docker_runner.rb +265 -0
  26. data/spec/shared/lib/mrss/lite_constraints.rb +16 -0
  27. data/spec/shared/lib/mrss/server_version_registry.rb +115 -0
  28. data/spec/shared/lib/mrss/spec_organizer.rb +3 -0
  29. data/spec/shared/lib/mrss/utils.rb +15 -0
  30. data/spec/shared/share/Dockerfile.erb +231 -0
  31. data/spec/shared/shlib/distro.sh +73 -0
  32. data/spec/shared/shlib/server.sh +290 -0
  33. data/spec/shared/shlib/set_env.sh +128 -0
  34. data/spec/support/client_registry.rb +8 -4
  35. data/spec/support/client_registry_macros.rb +14 -5
  36. data/spec/support/spec_config.rb +12 -0
  37. data/spec/support/spec_setup.rb +48 -38
  38. data.tar.gz.sig +0 -0
  39. metadata +998 -978
  40. metadata.gz.sig +0 -0
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e1730c9274095cd8113fe9ac6d8f48b82ea3228aeb0b327988ab580105c745e3
4
- data.tar.gz: d8a224877facc2e078dceb63c01eb9351f558ec9ea8a42b9264b909a77855d56
3
+ metadata.gz: 41f37eb33cbd1ebf2c916187b4610eefd895885042eeb3949882ce0a8c4ed069
4
+ data.tar.gz: db734108633f8b5988eaa15de33165182233ba5064f0b805298747256fb578b1
5
5
  SHA512:
6
- metadata.gz: 93e0f291aa4e52e81decda048473b8330eac80c17251cde83fb66592800d066d14010142893fabb00d896cdf409aa0bc7dd25feba3ca27b443d94cd44a6542e6
7
- data.tar.gz: 6e19b5c2a3f846ae7ffb0feab92b92bbfb0d88d21536d8e66eaccfc63f3dc8236cf7672b6aa23e9d51696135138529819f7fd3fff122c4d1608f8bf6081086b8
6
+ metadata.gz: 27c0c7ca84b6b7983767eb652f6aa5968362d8b42a4adf3eab3ee4a11fe4e74d36096b636436ac5075b31207470a67a8c5ecb00eac7f27a3889966ee30d84db9
7
+ data.tar.gz: 86c9fb09b3fb9c9512db2e7caed2f21ac2d53ee75f671d1cbcc92b89afa0d471cc1217552c3971ee9641f90b4c710692ab885c454f8701371726623e16114604
checksums.yaml.gz.sig CHANGED
Binary file
@@ -573,6 +573,8 @@ module Mongo
573
573
  # @param [ Array<Hash> ] documents The documents to insert.
574
574
  # @param [ Hash ] options The insert options.
575
575
  #
576
+ # @option options [ true | false ] :ordered Whether the operations
577
+ # should be executed in order.
576
578
  # @option options [ Session ] :session The session to use for the operation.
577
579
  #
578
580
  # @return [ Result ] The database response wrapper.
@@ -315,8 +315,20 @@ module Mongo
315
315
 
316
316
  # Get the Grid "filesystem" for this database.
317
317
  #
318
- # @example Get the GridFS.
319
- # database.fs
318
+ # @param [ Hash ] options The GridFS options.
319
+ #
320
+ # @option options [ String ] :bucket_name The prefix for the files and chunks
321
+ # collections.
322
+ # @option options [ Integer ] :chunk_size Override the default chunk
323
+ # size.
324
+ # @option options [ String ] :fs_name The prefix for the files and chunks
325
+ # collections.
326
+ # @option options [ String ] :read The read preference.
327
+ # @option options [ Session ] :session The session to use.
328
+ # @option options [ Hash ] :write Deprecated. Equivalent to :write_concern
329
+ # option.
330
+ # @option options [ Hash ] :write_concern The write concern options.
331
+ # Can be :w => Integer|String, :fsync => Boolean, :j => Boolean.
320
332
  #
321
333
  # @return [ Grid::FSBucket ] The GridFS for the database.
322
334
  #
@@ -36,6 +36,43 @@ module Mongo
36
36
  # @since 2.1.0
37
37
  FILES_INDEX = { filename: 1, uploadDate: 1 }.freeze
38
38
 
39
+ # Create the GridFS.
40
+ #
41
+ # @example Create the GridFS.
42
+ # Grid::FSBucket.new(database)
43
+ #
44
+ # @param [ Database ] database The database the files reside in.
45
+ # @param [ Hash ] options The GridFS options.
46
+ #
47
+ # @option options [ String ] :bucket_name The prefix for the files and chunks
48
+ # collections.
49
+ # @option options [ Integer ] :chunk_size Override the default chunk
50
+ # size.
51
+ # @option options [ String ] :fs_name The prefix for the files and chunks
52
+ # collections.
53
+ # @option options [ String ] :read The read preference.
54
+ # @option options [ Session ] :session The session to use.
55
+ # @option options [ Hash ] :write Deprecated. Equivalent to :write_concern
56
+ # option.
57
+ # @option options [ Hash ] :write_concern The write concern options.
58
+ # Can be :w => Integer|String, :fsync => Boolean, :j => Boolean.
59
+ #
60
+ # @since 2.0.0
61
+ def initialize(database, options = {})
62
+ @database = database
63
+ @options = options.dup
64
+ =begin WriteConcern object support
65
+ if @options[:write_concern].is_a?(WriteConcern::Base)
66
+ # Cache the instance so that we do not needlessly reconstruct it.
67
+ @write_concern = @options[:write_concern]
68
+ @options[:write_concern] = @write_concern.options
69
+ end
70
+ =end
71
+ @options.freeze
72
+ @chunks_collection = database[chunks_name]
73
+ @files_collection = database[files_name]
74
+ end
75
+
39
76
  # @return [ Collection ] chunks_collection The chunks collection.
40
77
  #
41
78
  # @since 2.0.0
@@ -133,43 +170,6 @@ module Mongo
133
170
  file.id
134
171
  end
135
172
 
136
- # Create the GridFS.
137
- #
138
- # @example Create the GridFS.
139
- # Grid::FSBucket.new(database)
140
- #
141
- # @param [ Database ] database The database the files reside in.
142
- # @param [ Hash ] options The GridFS options.
143
- #
144
- # @option options [ String ] :fs_name The prefix for the files and chunks
145
- # collections.
146
- # @option options [ String ] :bucket_name The prefix for the files and chunks
147
- # collections.
148
- # @option options [ Integer ] :chunk_size Override the default chunk
149
- # size.
150
- # @option options [ String ] :read The read preference.
151
- # @option options [ Session ] :session The session to use.
152
- # @option options [ Hash ] :write Deprecated. Equivalent to :write_concern
153
- # option.
154
- # @option options [ Hash ] :write_concern The write concern options.
155
- # Can be :w => Integer|String, :fsync => Boolean, :j => Boolean.
156
- #
157
- # @since 2.0.0
158
- def initialize(database, options = {})
159
- @database = database
160
- @options = options.dup
161
- =begin WriteConcern object support
162
- if @options[:write_concern].is_a?(WriteConcern::Base)
163
- # Cache the instance so that we do not needlessly reconstruct it.
164
- @write_concern = @options[:write_concern]
165
- @options[:write_concern] = @write_concern.options
166
- end
167
- =end
168
- @options.freeze
169
- @chunks_collection = database[chunks_name]
170
- @files_collection = database[files_name]
171
- end
172
-
173
173
  # Get the prefix for the GridFS
174
174
  #
175
175
  # @example Get the prefix.
@@ -37,8 +37,7 @@ module Mongo
37
37
  read_concern)
38
38
  end
39
39
  sel[:maxTimeMS] = max_time_ms if max_time_ms
40
- update_selector_for_read_pref(sel, connection)
41
- sel
40
+ add_read_preference_legacy(sel, connection)
42
41
  end
43
42
 
44
43
  def message(connection)
@@ -36,47 +36,44 @@ module Mongo
36
36
  #
37
37
  # @since 2.0.0
38
38
  def options(connection)
39
- add_slave_ok_flag_maybe(super, connection)
39
+ options = super
40
+ if add_slave_ok_flag?(connection)
41
+ flags = options[:flags]&.dup || []
42
+ flags << :slave_ok
43
+ options = options.merge(flags: flags)
44
+ end
45
+ options
40
46
  end
41
47
 
42
- # Adds :slave_ok flag to options based on the read preference specified
43
- # in the operation or implied by the topology that the connection's
44
- # server is a part of.
48
+ # Whether to add the :slave_ok flag to the request based on the
49
+ # read preference specified in the operation or implied by the topology
50
+ # that the connection's server is a part of.
45
51
  #
46
- # @param [ Hash ] options The options calculated so far.
47
52
  # @param [ Server::Connection ] connection The connection that the
48
53
  # operation will be executed on.
49
54
  #
50
- # @return [ Hash ] The new options.
51
- def add_slave_ok_flag_maybe(options, connection)
52
- add_flag =
53
- # https://github.com/mongodb/specifications/blob/master/source/server-selection/server-selection.rst#topology-type-single
54
- if connection.description.standalone?
55
- # Read preference is never sent to standalones.
56
- false
57
- elsif connection.server.cluster.single?
58
- # In Single topology the driver forces primaryPreferred read
59
- # preference mode (via the slave_ok flag, in case of old servers)
60
- # so that the query is satisfied.
61
- true
62
- else
63
- # In replica sets and sharded clusters, read preference is passed
64
- # to the server if one is specified by the application, and there
65
- # is no default.
66
- read && read.slave_ok?
67
- end
68
-
69
- if add_flag
70
- options= options.dup
71
- (options[:flags] ||= []) << :slave_ok
55
+ # @return [ true | false ] Whether the :slave_ok flag should be added.
56
+ def add_slave_ok_flag?(connection)
57
+ # https://github.com/mongodb/specifications/blob/master/source/server-selection/server-selection.rst#topology-type-single
58
+ if connection.description.standalone?
59
+ # Read preference is never sent to standalones.
60
+ false
61
+ elsif connection.server.cluster.single?
62
+ # In Single topology the driver forces primaryPreferred read
63
+ # preference mode (via the slave_ok flag, in case of old servers)
64
+ # so that the query is satisfied.
65
+ true
66
+ else
67
+ # In replica sets and sharded clusters, read preference is passed
68
+ # to the server if one is specified by the application, and there
69
+ # is no default.
70
+ read && read.slave_ok? || false
72
71
  end
73
-
74
- options
75
72
  end
76
73
 
77
74
  def command(connection)
78
75
  sel = super
79
- update_selector_for_read_pref(sel, connection)
76
+ add_read_preference_legacy(sel, connection)
80
77
  end
81
78
 
82
79
  # Adds $readPreference field to the command document.
@@ -95,14 +92,19 @@ module Mongo
95
92
  # operation will be executed on.
96
93
  #
97
94
  # @return [ Hash ] New command document to send to the server.
98
- def update_selector_for_read_pref(sel, connection)
95
+ def add_read_preference_legacy(sel, connection)
99
96
  if read && connection.description.mongos? && read_pref = read.to_mongos
100
- Mongo::Lint.validate_camel_case_read_preference(read_pref)
101
- sel = sel[:$query] ? sel : {:$query => sel}
102
- sel = sel.merge(:$readPreference => read_pref)
103
- else
104
- sel
97
+ # If the read preference contains only mode and mode is secondary
98
+ # preferred and we are sending to a pre-OP_MSG server, this read
99
+ # preference is indicated by the :slave_ok wire protocol flag
100
+ # and $readPreference command parameter isn't sent.
101
+ if read_pref != {mode: 'secondaryPreferred'}
102
+ Mongo::Lint.validate_camel_case_read_preference(read_pref)
103
+ sel = sel[:$query] ? sel : {:$query => sel}
104
+ sel = sel.merge(:$readPreference => read_pref)
105
+ end
105
106
  end
107
+ sel
106
108
  end
107
109
  end
108
110
  end
@@ -170,9 +170,10 @@ module Mongo
170
170
  elsif connection.description.mongos?
171
171
  # When server is a mongos:
172
172
  # - $readPreference is never sent when mode is 'primary'
173
- # - When mode is 'secondaryPreferred' $readPreference is only sent
174
- # when a non-mode field (i.e. tag_sets) is present
175
173
  # - Otherwise $readPreference is sent
174
+ # When mode is 'secondaryPreferred' $readPreference is currently
175
+ # required to only be sent when a non-mode field (i.e. tag_sets)
176
+ # is present, but this causes wrong behavior (DRIVERS-1642).
176
177
  if read
177
178
  doc = read.to_mongos
178
179
  if doc
@@ -43,8 +43,8 @@ module Mongo
43
43
  # Msg.new([:more_to_come], {}, { ismaster: 1 },
44
44
  # { type: 1, payload: { identifier: 'documents', sequence: [..] } })
45
45
  #
46
- # @param [ Array<Symbol> ] flags The flag bits. Current supported values
47
- # are :more_to_come and :checksum_present.
46
+ # @param [ Array<Symbol> ] flags The flag bits. Currently supported
47
+ # values are :more_to_come and :checksum_present.
48
48
  # @param [ Hash ] options The options.
49
49
  # @param [ BSON::Document, Hash ] main_document The document that will
50
50
  # become the payload type 0 section. Can contain global args as they
@@ -46,18 +46,18 @@ module Mongo
46
46
  # @example Find all user ids.
47
47
  # Query.new('xgen', 'users', {}, :fields => {:id => 1})
48
48
  #
49
- # @param database [String, Symbol] The database to query.
50
- # @param collection [String, Symbol] The collection to query.
51
- # @param selector [Hash] The query selector.
52
- # @param options [Hash] The additional query options.
49
+ # @param [ String, Symbol ] database The database to query.
50
+ # @param [ String, Symbol ] collection The collection to query.
51
+ # @param [ Hash ] selector The query selector.
52
+ # @param [ Hash ] options The additional query options.
53
53
  #
54
- # @option options :project [Hash] The projection.
55
- # @option options :skip [Integer] The number of documents to skip.
56
- # @option options :limit [Integer] The number of documents to return.
57
- # @option options :flags [Array] The flags for the query message.
58
- #
59
- # Supported flags: +:tailable_cursor+, +:slave_ok+, +:oplog_replay+,
60
- # +:no_cursor_timeout+, +:await_data+, +:exhaust+, +:partial+
54
+ # @option options [ Array<Symbol> ] :flags The flag bits.
55
+ # Currently supported values are :await_data, :exhaust,
56
+ # :no_cursor_timeout, :oplog_replay, :partial, :slave_ok,
57
+ # :tailable_cursor.
58
+ # @option options [ Integer ] :limit The number of documents to return.
59
+ # @option options [ Hash ] :project The projection.
60
+ # @option options [ Integer ] :skip The number of documents to skip.
61
61
  def initialize(database, collection, selector, options = {})
62
62
  @database = database
63
63
  @namespace = "#{database}.#{collection}"
@@ -86,13 +86,8 @@ module Mongo
86
86
  #
87
87
  # @since 2.0.0
88
88
  def to_mongos
89
- if tag_sets.empty? && max_staleness.nil? && hedge.nil?
90
- # The server preference is not sent to mongos as part of the query
91
- # selector if there are no tag sets, for maximum backwards compatibility.
92
- nil
93
- else
94
- to_doc
95
- end
89
+ # Always send the read preference to mongos: DRIVERS-1642.
90
+ to_doc
96
91
  end
97
92
 
98
93
  private
data/lib/mongo/version.rb CHANGED
@@ -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.13.2'.freeze
20
+ VERSION = '2.13.3'.freeze
21
21
  end
@@ -1,7 +1,7 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe 'SDAM error handling' do
4
- clean_slate_for_all
4
+ clean_slate
5
5
 
6
6
  after do
7
7
  # Close all clients after every test to avoid leaking expectations into
@@ -67,10 +67,8 @@ describe 'SDAM events' do
67
67
  started_events.length.should <= 10
68
68
 
69
69
  succeeded_events = subscriber.select_succeeded_events(Mongo::Monitoring::Event::ServerHeartbeatSucceeded)
70
- # Since we gracefully close the client, we expect each heartbeat
71
- # to complete.
72
70
  started_events.length.should > 1
73
- (succeeded_events.length-1..succeeded_events.length).should include(started_events.length)
71
+ (succeeded_events.length..succeeded_events.length+1).should include(started_events.length)
74
72
  end
75
73
  end
76
74
 
@@ -109,9 +107,9 @@ describe 'SDAM events' do
109
107
  # There may be in-flight ismasters that don't complete, both
110
108
  # regular and awaited.
111
109
  started_awaited.length.should > 1
112
- (succeeded_awaited.length-1..succeeded_awaited.length).should include(started_awaited.length)
110
+ (succeeded_awaited.length..succeeded_awaited.length+1).should include(started_awaited.length)
113
111
  started_regular.length.should > 1
114
- (succeeded_regular.length-1..succeeded_regular.length).should include(started_regular.length)
112
+ (succeeded_regular.length..succeeded_regular.length+1).should include(started_regular.length)
115
113
  end
116
114
  end
117
115
  end
@@ -0,0 +1,102 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'Secondary reads' do
4
+ before do
5
+ root_authorized_client.use('sr')['secondary_reads'].drop
6
+ root_authorized_client.use('sr')['secondary_reads'].insert_one(test: 1)
7
+ end
8
+
9
+ shared_examples 'performs reads as per read preference' do
10
+
11
+ %i(primary primary_preferred).each do |mode|
12
+
13
+ context mode.inspect do
14
+
15
+ let(:client) do
16
+ root_authorized_client.with(read: {mode: mode}).use('sr')
17
+ end
18
+
19
+ it 'reads from primary' do
20
+ start_stats = get_read_counters
21
+
22
+ 30.times do
23
+ client['secondary_reads'].find.to_a
24
+ end
25
+
26
+ end_stats = get_read_counters
27
+
28
+ end_stats[:secondary].should be_within(10).of(start_stats[:secondary])
29
+ end_stats[:primary].should >= start_stats[:primary] + 30
30
+ end
31
+ end
32
+ end
33
+
34
+ %i(secondary secondary_preferred).each do |mode|
35
+
36
+ context mode.inspect do
37
+ let(:client) do
38
+ root_authorized_client.with(read: {mode: mode}).use('sr')
39
+ end
40
+
41
+ it 'reads from secondaries' do
42
+ start_stats = get_read_counters
43
+
44
+ 30.times do
45
+ client['secondary_reads'].find.to_a
46
+ end
47
+
48
+ end_stats = get_read_counters
49
+
50
+ end_stats[:primary].should be_within(10).of(start_stats[:primary])
51
+ end_stats[:secondary].should >= start_stats[:secondary] + 30
52
+ end
53
+ end
54
+ end
55
+ end
56
+
57
+ context 'replica set' do
58
+ require_topology :replica_set
59
+
60
+ include_examples 'performs reads as per read preference'
61
+ end
62
+
63
+ context 'sharded cluster' do
64
+ require_topology :sharded
65
+
66
+ include_examples 'performs reads as per read preference'
67
+ end
68
+
69
+ def get_read_counters
70
+ client = ClientRegistry.instance.global_client('root_authorized')
71
+ addresses = []
72
+ if client.cluster.sharded?
73
+ doc = client.use('admin').command(listShards: 1).documents.first
74
+ doc['shards'].each do |shard|
75
+ addresses += shard['host'].split('/').last.split(',')
76
+ end
77
+ else
78
+ client.cluster.servers.each do |server|
79
+ next unless server.primary? || server.secondary?
80
+ addresses << server.address.seed
81
+ end
82
+ end
83
+ stats = Hash.new(0)
84
+ addresses.each do |address|
85
+ ClientRegistry.instance.new_local_client(
86
+ [address],
87
+ SpecConfig.instance.all_test_options.merge(connect: :direct),
88
+ ) do |c|
89
+ server = c.cluster.servers.first
90
+ next unless server.primary? || server.secondary?
91
+ stat = c.command(serverStatus: 1).documents.first
92
+ queries = stat['opcounters']['query']
93
+ if server.primary?
94
+ stats[:primary] += queries
95
+ else
96
+ stats[:secondary] += queries
97
+ end
98
+ end
99
+ end
100
+ stats
101
+ end
102
+ end