mongo 2.14.0 → 2.14.1
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.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data/lib/mongo/background_thread.rb +11 -0
- data/lib/mongo/cluster/sdam_flow.rb +14 -0
- data/lib/mongo/cluster.rb +0 -26
- data/lib/mongo/collection/view/iterable.rb +16 -6
- data/lib/mongo/collection.rb +2 -0
- data/lib/mongo/cursor.rb +10 -0
- data/lib/mongo/database.rb +14 -2
- data/lib/mongo/grid/fs_bucket.rb +37 -37
- data/lib/mongo/operation/parallel_scan/command.rb +1 -2
- data/lib/mongo/operation/shared/read_preference_supported.rb +38 -36
- data/lib/mongo/operation/shared/sessions_supported.rb +3 -2
- data/lib/mongo/protocol/msg.rb +2 -2
- data/lib/mongo/protocol/query.rb +11 -11
- data/lib/mongo/server/connection_pool.rb +0 -2
- data/lib/mongo/server.rb +0 -14
- data/lib/mongo/server_selector/secondary_preferred.rb +2 -7
- data/lib/mongo/srv/monitor.rb +0 -11
- data/lib/mongo/version.rb +1 -1
- data/spec/integration/query_cache_spec.rb +45 -0
- data/spec/integration/sdam_error_handling_spec.rb +1 -1
- data/spec/integration/sdam_events_spec.rb +3 -5
- data/spec/integration/secondary_reads_spec.rb +102 -0
- data/spec/mongo/cluster_spec.rb +2 -18
- data/spec/mongo/index/view_spec.rb +4 -2
- data/spec/mongo/operation/read_preference_legacy_spec.rb +9 -19
- data/spec/mongo/operation/read_preference_op_msg_spec.rb +3 -3
- data/spec/mongo/server/app_metadata_shared.rb +33 -7
- data/spec/mongo/server_selector/secondary_preferred_spec.rb +6 -6
- data/spec/runners/transactions/operation.rb +13 -2
- data/spec/shared/bin/get-mongodb-download-url +17 -0
- data/spec/shared/lib/mrss/cluster_config.rb +221 -0
- data/spec/shared/lib/mrss/constraints.rb +43 -0
- data/spec/shared/lib/mrss/docker_runner.rb +265 -0
- data/spec/shared/lib/mrss/lite_constraints.rb +16 -0
- data/spec/shared/lib/mrss/server_version_registry.rb +115 -0
- data/spec/shared/lib/mrss/spec_organizer.rb +3 -0
- data/spec/shared/lib/mrss/utils.rb +15 -0
- data/spec/shared/share/Dockerfile.erb +231 -0
- data/spec/shared/shlib/distro.sh +73 -0
- data/spec/shared/shlib/server.sh +290 -0
- data/spec/shared/shlib/set_env.sh +128 -0
- data/spec/solo/clean_exit_spec.rb +21 -0
- data/spec/support/client_registry.rb +8 -4
- data/spec/support/client_registry_macros.rb +4 -4
- data/spec/support/spec_config.rb +12 -0
- data/spec/support/spec_setup.rb +48 -38
- data.tar.gz.sig +0 -0
- metadata +1005 -983
- metadata.gz.sig +0 -0
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA256:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: 02e085995ec501175b551369fff92fd59b44787da27cb9f84b93dafef4d0762b
         | 
| 4 | 
            +
              data.tar.gz: f7ac041c7d89ad98207a6038ab44263aed36ae4fbdc925107a0f74772889ff48
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: 61512bc1653f1b2d9e5d73db7acbfd0725931cf7e234aad7b709086e76037f287da12e6c893c6ae84429113fd83cf195a296e0f3f01fa3974670106d1b19e8d4
         | 
| 7 | 
            +
              data.tar.gz: 198f03ef56d8f280962ca212e411bf97a04cd518d7e1f82628f3bf4c274cf897c872e1d109af1ee94627803de2d3d8b37afbd239f87fe1c6a74e6813a2f65201
         | 
    
        checksums.yaml.gz.sig
    CHANGED
    
    | Binary file | 
| @@ -20,6 +20,17 @@ module Mongo | |
| 20 20 | 
             
              # compatibility reasons. However using these methods outside of the driver
         | 
| 21 21 | 
             
              # is deprecated.
         | 
| 22 22 | 
             
              #
         | 
| 23 | 
            +
              # @note Do not start or stop background threads in finalizers. See
         | 
| 24 | 
            +
              #   https://jira.mongodb.org/browse/RUBY-2453 and
         | 
| 25 | 
            +
              #   https://bugs.ruby-lang.org/issues/16288. When interpreter exits,
         | 
| 26 | 
            +
              #   background threads are stopped first and finalizers are invoked next,
         | 
| 27 | 
            +
              #   and MRI's internal data structures are basically corrupt at this point
         | 
| 28 | 
            +
              #   if threads are being referenced. Prior to interpreter shutdown this
         | 
| 29 | 
            +
              #   means threads cannot be stopped by objects going out of scope, but
         | 
| 30 | 
            +
              #   most likely the threads hold references to said objects anyway if
         | 
| 31 | 
            +
              #   work is being performed thus the objects wouldn't go out of scope in
         | 
| 32 | 
            +
              #   the first place.
         | 
| 33 | 
            +
              #
         | 
| 23 34 | 
             
              # @api private
         | 
| 24 35 | 
             
              module BackgroundThread
         | 
| 25 36 | 
             
                include Loggable
         | 
| @@ -178,6 +178,7 @@ class Mongo::Cluster | |
| 178 178 | 
             
                    raise ArgumentError, "Unknown topology #{topology.class}"
         | 
| 179 179 | 
             
                  end
         | 
| 180 180 |  | 
| 181 | 
            +
                  verify_invariants
         | 
| 181 182 | 
             
                  commit_changes
         | 
| 182 183 | 
             
                  disconnect_servers
         | 
| 183 184 | 
             
                end
         | 
| @@ -363,6 +364,9 @@ class Mongo::Cluster | |
| 363 364 | 
             
                      end
         | 
| 364 365 | 
             
                    end
         | 
| 365 366 | 
             
                  end
         | 
| 367 | 
            +
             | 
| 368 | 
            +
                  verify_invariants
         | 
| 369 | 
            +
             | 
| 366 370 | 
             
                  added_servers
         | 
| 367 371 | 
             
                end
         | 
| 368 372 |  | 
| @@ -599,5 +603,15 @@ class Mongo::Cluster | |
| 599 603 |  | 
| 600 604 | 
             
                  @previous_server_descriptions != server_descriptions
         | 
| 601 605 | 
             
                end
         | 
| 606 | 
            +
             | 
| 607 | 
            +
                def verify_invariants
         | 
| 608 | 
            +
                  if Mongo::Lint.enabled?
         | 
| 609 | 
            +
                    if cluster.topology.single?
         | 
| 610 | 
            +
                      if cluster.servers_list.length > 1
         | 
| 611 | 
            +
                        raise Mongo::Error::LintError, "Trying to create a single topology with multiple servers: #{cluster.servers_list}"
         | 
| 612 | 
            +
                      end
         | 
| 613 | 
            +
                    end
         | 
| 614 | 
            +
                  end
         | 
| 615 | 
            +
                end
         | 
| 602 616 | 
             
              end
         | 
| 603 617 | 
             
            end
         | 
    
        data/lib/mongo/cluster.rb
    CHANGED
    
    | @@ -199,9 +199,6 @@ module Mongo | |
| 199 199 | 
             
                      @cursor_reaper, @socket_reaper,
         | 
| 200 200 | 
             
                    ], options)
         | 
| 201 201 |  | 
| 202 | 
            -
                    ObjectSpace.define_finalizer(self, self.class.finalize(
         | 
| 203 | 
            -
                      {}, @periodic_executor, @session_pool))
         | 
| 204 | 
            -
             | 
| 205 202 | 
             
                    @periodic_executor.run!
         | 
| 206 203 | 
             
                  end
         | 
| 207 204 |  | 
| @@ -445,25 +442,6 @@ module Mongo | |
| 445 442 | 
             
                # @api private
         | 
| 446 443 | 
             
                attr_reader :server_selection_semaphore
         | 
| 447 444 |  | 
| 448 | 
            -
                # Finalize the cluster for garbage collection.
         | 
| 449 | 
            -
                #
         | 
| 450 | 
            -
                # @example Finalize the cluster.
         | 
| 451 | 
            -
                #   Cluster.finalize(pools)
         | 
| 452 | 
            -
                #
         | 
| 453 | 
            -
                # @param [ Hash<Address, Server::ConnectionPool> ] pools Ignored.
         | 
| 454 | 
            -
                # @param [ PeriodicExecutor ] periodic_executor The periodic executor.
         | 
| 455 | 
            -
                # @param [ SessionPool ] session_pool The session pool.
         | 
| 456 | 
            -
                #
         | 
| 457 | 
            -
                # @return [ Proc ] The Finalizer.
         | 
| 458 | 
            -
                #
         | 
| 459 | 
            -
                # @since 2.2.0
         | 
| 460 | 
            -
                def self.finalize(pools, periodic_executor, session_pool)
         | 
| 461 | 
            -
                  proc do
         | 
| 462 | 
            -
                    session_pool.end_sessions
         | 
| 463 | 
            -
                    periodic_executor.stop!
         | 
| 464 | 
            -
                  end
         | 
| 465 | 
            -
                end
         | 
| 466 | 
            -
             | 
| 467 445 | 
             
                # Closes the cluster.
         | 
| 468 446 | 
             
                #
         | 
| 469 447 | 
             
                # @note Applications should call Client#close to disconnect from
         | 
| @@ -953,10 +931,6 @@ module Mongo | |
| 953 931 | 
             
                        monitor_options = Utils.shallow_symbolize_keys(options.merge(
         | 
| 954 932 | 
             
                          timeout: options[:connect_timeout] || Server::CONNECT_TIMEOUT))
         | 
| 955 933 | 
             
                        @srv_monitor = _srv_monitor = Srv::Monitor.new(self, **monitor_options)
         | 
| 956 | 
            -
                        finalizer = lambda do
         | 
| 957 | 
            -
                          _srv_monitor.stop!
         | 
| 958 | 
            -
                        end
         | 
| 959 | 
            -
                        ObjectSpace.define_finalizer(self, finalizer)
         | 
| 960 934 | 
             
                      end
         | 
| 961 935 | 
             
                      @srv_monitor.run!
         | 
| 962 936 | 
             
                    end
         | 
| @@ -35,18 +35,28 @@ module Mongo | |
| 35 35 | 
             
                    #
         | 
| 36 36 | 
             
                    # @yieldparam [ Hash ] Each matching document.
         | 
| 37 37 | 
             
                    def each
         | 
| 38 | 
            -
                       | 
| 38 | 
            +
                      # If the caching cursor is closed and was not fully iterated,
         | 
| 39 | 
            +
                      # the documents we have in it are not the complete result set and
         | 
| 40 | 
            +
                      # we have no way of completing that iteration.
         | 
| 41 | 
            +
                      # Therefore, discard that cursor and start iteration again.
         | 
| 42 | 
            +
                      # The case of the caching cursor not being closed and not having
         | 
| 43 | 
            +
                      # been fully iterated isn't tested - see RUBY-2773.
         | 
| 44 | 
            +
                      @cursor = if use_query_cache? && cached_cursor && (
         | 
| 45 | 
            +
                        cached_cursor.fully_iterated? || !cached_cursor.closed?
         | 
| 46 | 
            +
                      )
         | 
| 39 47 | 
             
                        cached_cursor
         | 
| 40 48 | 
             
                      else
         | 
| 41 49 | 
             
                        session = client.send(:get_session, @options)
         | 
| 42 | 
            -
                        select_cursor(session)
         | 
| 50 | 
            +
                        select_cursor(session).tap do |cursor|
         | 
| 51 | 
            +
                          if use_query_cache?
         | 
| 52 | 
            +
                            # No need to store the cursor in the query cache if there is
         | 
| 53 | 
            +
                            # already a cached cursor stored at this key.
         | 
| 54 | 
            +
                            QueryCache.set(cursor, **cache_options)
         | 
| 55 | 
            +
                          end
         | 
| 56 | 
            +
                        end
         | 
| 43 57 | 
             
                      end
         | 
| 44 58 |  | 
| 45 59 | 
             
                      if use_query_cache?
         | 
| 46 | 
            -
                        # No need to store the cursor in the query cache if there is
         | 
| 47 | 
            -
                        # already a cached cursor stored at this key.
         | 
| 48 | 
            -
                        QueryCache.set(@cursor, **cache_options) unless cached_cursor
         | 
| 49 | 
            -
             | 
| 50 60 | 
             
                        # If a query with a limit is performed, the query cache will
         | 
| 51 61 | 
             
                        # re-use results from an earlier query with the same or larger
         | 
| 52 62 | 
             
                        # limit, and then impose the lower limit during iteration.
         | 
    
        data/lib/mongo/collection.rb
    CHANGED
    
    | @@ -593,6 +593,8 @@ module Mongo | |
| 593 593 | 
             
                # @param [ Array<Hash> ] documents The documents to insert.
         | 
| 594 594 | 
             
                # @param [ Hash ] options The insert options.
         | 
| 595 595 | 
             
                #
         | 
| 596 | 
            +
                # @option options [ true | false ] :ordered Whether the operations
         | 
| 597 | 
            +
                #   should be executed in order.
         | 
| 596 598 | 
             
                # @option options [ Session ] :session The session to use for the operation.
         | 
| 597 599 | 
             
                #
         | 
| 598 600 | 
             
                # @return [ Result ] The database response wrapper.
         | 
    
        data/lib/mongo/cursor.rb
    CHANGED
    
    | @@ -209,10 +209,12 @@ module Mongo | |
| 209 209 | 
             
                    unless closed?
         | 
| 210 210 | 
             
                      if exhausted?
         | 
| 211 211 | 
             
                        close
         | 
| 212 | 
            +
                        @fully_iterated = true
         | 
| 212 213 | 
             
                        raise StopIteration
         | 
| 213 214 | 
             
                      end
         | 
| 214 215 | 
             
                      @documents = get_more
         | 
| 215 216 | 
             
                    else
         | 
| 217 | 
            +
                      @fully_iterated = true
         | 
| 216 218 | 
             
                      raise StopIteration
         | 
| 217 219 | 
             
                    end
         | 
| 218 220 | 
             
                  else
         | 
| @@ -229,6 +231,9 @@ module Mongo | |
| 229 231 | 
             
                  # over the last document, or if the batch is empty
         | 
| 230 232 | 
             
                  if @documents.size <= 1
         | 
| 231 233 | 
             
                    cache_batch_resume_token
         | 
| 234 | 
            +
                    if closed?
         | 
| 235 | 
            +
                      @fully_iterated = true
         | 
| 236 | 
            +
                    end
         | 
| 232 237 | 
             
                  end
         | 
| 233 238 |  | 
| 234 239 | 
             
                  return @documents.shift
         | 
| @@ -348,6 +353,11 @@ module Mongo | |
| 348 353 | 
             
                  process(get_more_operation.execute(@server, client: client))
         | 
| 349 354 | 
             
                end
         | 
| 350 355 |  | 
| 356 | 
            +
                # @api private
         | 
| 357 | 
            +
                def fully_iterated?
         | 
| 358 | 
            +
                  !!@fully_iterated
         | 
| 359 | 
            +
                end
         | 
| 360 | 
            +
             | 
| 351 361 | 
             
                private
         | 
| 352 362 |  | 
| 353 363 | 
             
                def exhausted?
         | 
    
        data/lib/mongo/database.rb
    CHANGED
    
    | @@ -321,8 +321,20 @@ module Mongo | |
| 321 321 |  | 
| 322 322 | 
             
                # Get the Grid "filesystem" for this database.
         | 
| 323 323 | 
             
                #
         | 
| 324 | 
            -
                # @ | 
| 325 | 
            -
                # | 
| 324 | 
            +
                # @param [ Hash ] options The GridFS options.
         | 
| 325 | 
            +
                #
         | 
| 326 | 
            +
                # @option options [ String ] :bucket_name The prefix for the files and chunks
         | 
| 327 | 
            +
                #   collections.
         | 
| 328 | 
            +
                # @option options [ Integer ] :chunk_size Override the default chunk
         | 
| 329 | 
            +
                #   size.
         | 
| 330 | 
            +
                # @option options [ String ] :fs_name The prefix for the files and chunks
         | 
| 331 | 
            +
                #   collections.
         | 
| 332 | 
            +
                # @option options [ String ] :read The read preference.
         | 
| 333 | 
            +
                # @option options [ Session ] :session The session to use.
         | 
| 334 | 
            +
                # @option options [ Hash ] :write Deprecated. Equivalent to :write_concern
         | 
| 335 | 
            +
                #   option.
         | 
| 336 | 
            +
                # @option options [ Hash ] :write_concern The write concern options.
         | 
| 337 | 
            +
                #   Can be :w => Integer|String, :fsync => Boolean, :j => Boolean.
         | 
| 326 338 | 
             
                #
         | 
| 327 339 | 
             
                # @return [ Grid::FSBucket ] The GridFS for the database.
         | 
| 328 340 | 
             
                #
         | 
    
        data/lib/mongo/grid/fs_bucket.rb
    CHANGED
    
    | @@ -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.
         | 
| @@ -36,47 +36,44 @@ module Mongo | |
| 36 36 | 
             
                  #
         | 
| 37 37 | 
             
                  # @since 2.0.0
         | 
| 38 38 | 
             
                  def options(connection)
         | 
| 39 | 
            -
                     | 
| 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 | 
            -
                  #  | 
| 43 | 
            -
                  # in the operation or implied by the topology | 
| 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 [  | 
| 51 | 
            -
                  def  | 
| 52 | 
            -
                     | 
| 53 | 
            -
             | 
| 54 | 
            -
                       | 
| 55 | 
            -
             | 
| 56 | 
            -
             | 
| 57 | 
            -
                       | 
| 58 | 
            -
             | 
| 59 | 
            -
             | 
| 60 | 
            -
             | 
| 61 | 
            -
             | 
| 62 | 
            -
                       | 
| 63 | 
            -
             | 
| 64 | 
            -
             | 
| 65 | 
            -
             | 
| 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 | 
            -
                     | 
| 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  | 
| 95 | 
            +
                  def add_read_preference_legacy(sel, connection)
         | 
| 99 96 | 
             
                    if read && connection.description.mongos? && read_pref = read.to_mongos
         | 
| 100 | 
            -
                       | 
| 101 | 
            -
                       | 
| 102 | 
            -
                       | 
| 103 | 
            -
             | 
| 104 | 
            -
                       | 
| 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
         | 
| @@ -171,9 +171,10 @@ module Mongo | |
| 171 171 | 
             
                    elsif connection.description.mongos?
         | 
| 172 172 | 
             
                      # When server is a mongos:
         | 
| 173 173 | 
             
                      # - $readPreference is never sent when mode is 'primary'
         | 
| 174 | 
            -
                      # - When mode is 'secondaryPreferred' $readPreference is only sent
         | 
| 175 | 
            -
                      #   when a non-mode field (i.e. tag_sets) is present
         | 
| 176 174 | 
             
                      # - Otherwise $readPreference is sent
         | 
| 175 | 
            +
                      # When mode is 'secondaryPreferred' $readPreference is currently
         | 
| 176 | 
            +
                      # required to only be sent when a non-mode field (i.e. tag_sets)
         | 
| 177 | 
            +
                      # is present, but this causes wrong behavior (DRIVERS-1642).
         | 
| 177 178 | 
             
                      if read
         | 
| 178 179 | 
             
                        doc = read.to_mongos
         | 
| 179 180 | 
             
                        if doc
         | 
    
        data/lib/mongo/protocol/msg.rb
    CHANGED
    
    | @@ -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.  | 
| 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
         | 
    
        data/lib/mongo/protocol/query.rb
    CHANGED
    
    | @@ -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  | 
| 50 | 
            -
                  # @param  | 
| 51 | 
            -
                  # @param  | 
| 52 | 
            -
                  # @param  | 
| 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  | 
| 55 | 
            -
                  #  | 
| 56 | 
            -
                  #  | 
| 57 | 
            -
                  # | 
| 58 | 
            -
                  #
         | 
| 59 | 
            -
                  # | 
| 60 | 
            -
                  # | 
| 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}"
         |