mongo 2.5.0 → 2.5.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.tar.gz.sig +0 -0
- data/README.md +2 -0
- data/Rakefile +4 -1
- data/lib/mongo/address.rb +2 -1
- data/lib/mongo/client.rb +6 -51
- data/lib/mongo/cluster.rb +34 -4
- data/lib/mongo/cluster/reapers/socket_reaper.rb +1 -1
- data/lib/mongo/cluster/topology/replica_set.rb +3 -1
- data/lib/mongo/collection.rb +6 -6
- data/lib/mongo/collection/view.rb +2 -4
- data/lib/mongo/cursor.rb +9 -4
- data/lib/mongo/error.rb +2 -0
- data/lib/mongo/operation/uses_command_op_msg.rb +1 -1
- data/lib/mongo/server.rb +3 -0
- data/lib/mongo/server/description.rb +1 -1
- data/lib/mongo/server/description/features.rb +18 -12
- data/lib/mongo/server_selector/selectable.rb +5 -1
- data/lib/mongo/session.rb +38 -43
- data/lib/mongo/session/session_pool.rb +12 -30
- data/lib/mongo/socket.rb +24 -0
- data/lib/mongo/socket/tcp.rb +0 -1
- data/lib/mongo/uri.rb +26 -5
- data/lib/mongo/version.rb +1 -1
- data/spec/mongo/address_spec.rb +37 -2
- data/spec/mongo/bulk_write_spec.rb +4 -10
- data/spec/mongo/change_stream_examples_spec.rb +40 -0
- data/spec/mongo/client_spec.rb +47 -12
- data/spec/mongo/cluster/topology/replica_set_spec.rb +2 -0
- data/spec/mongo/collection/view/aggregation_spec.rb +2 -8
- data/spec/mongo/collection/view/change_stream_spec.rb +1 -5
- data/spec/mongo/collection/view/map_reduce_spec.rb +2 -8
- data/spec/mongo/collection/view/readable_spec.rb +1 -1
- data/spec/mongo/collection_spec.rb +11 -29
- data/spec/mongo/crud_spec.rb +6 -2
- data/spec/mongo/cursor_spec.rb +84 -1
- data/spec/mongo/database_spec.rb +2 -8
- data/spec/mongo/dns_seedlist_discovery_spec.rb +67 -63
- data/spec/mongo/max_staleness_spec.rb +1 -0
- data/spec/mongo/retryable_writes_spec.rb +7 -9
- data/spec/mongo/sdam_spec.rb +42 -24
- data/spec/mongo/server/description/features_spec.rb +3 -3
- data/spec/mongo/server_selection_spec.rb +2 -0
- data/spec/mongo/server_selector_spec.rb +2 -0
- data/spec/mongo/session/session_pool_spec.rb +16 -22
- data/spec/mongo/session_spec.rb +13 -8
- data/spec/mongo/uri/srv_protocol_spec.rb +481 -478
- data/spec/mongo/uri_spec.rb +1 -1
- data/spec/spec_helper.rb +11 -63
- data/spec/support/authorization.rb +35 -1
- data/spec/support/connection_string_tests/invalid-uris.yml +27 -11
- data/spec/support/event_subscriber.rb +66 -0
- data/spec/support/sdam/rs/compatible.yml +41 -0
- data/spec/support/sdam/rs/discover_arbiters.yml +3 -1
- data/spec/support/sdam/rs/discover_passives.yml +6 -2
- data/spec/support/sdam/rs/discover_primary.yml +3 -1
- data/spec/support/sdam/rs/discover_secondary.yml +3 -1
- data/spec/support/sdam/rs/discovery.yml +12 -4
- data/spec/support/sdam/rs/equal_electionids.yml +6 -2
- data/spec/support/sdam/rs/ghost_discovered.yml +3 -1
- data/spec/support/sdam/rs/hosts_differ_from_seeds.yml +3 -1
- data/spec/support/sdam/rs/ls_timeout.yml +169 -14
- data/spec/support/sdam/rs/member_reconfig.yml +6 -2
- data/spec/support/sdam/rs/member_standalone.yml +6 -2
- data/spec/support/sdam/rs/new_primary.yml +6 -2
- data/spec/support/sdam/rs/new_primary_new_electionid.yml +9 -3
- data/spec/support/sdam/rs/new_primary_new_setversion.yml +9 -3
- data/spec/support/sdam/rs/new_primary_wrong_set_name.yml +6 -2
- data/spec/support/sdam/rs/non_rs_member.yml +3 -2
- data/spec/support/sdam/rs/normalize_case.yml +3 -1
- data/spec/support/sdam/rs/null_election_id.yml +12 -4
- data/spec/support/sdam/rs/primary_becomes_standalone.yml +6 -4
- data/spec/support/sdam/rs/primary_changes_set_name.yml +6 -2
- data/spec/support/sdam/rs/primary_disconnect.yml +3 -1
- data/spec/support/sdam/rs/primary_disconnect_electionid.yml +15 -5
- data/spec/support/sdam/rs/primary_disconnect_setversion.yml +15 -5
- data/spec/support/sdam/rs/primary_hint_from_secondary_with_mismatched_me.yml +6 -2
- data/spec/support/sdam/rs/primary_mismatched_me.yml +26 -37
- data/spec/support/sdam/rs/primary_reports_new_member.yml +12 -4
- data/spec/support/sdam/rs/primary_to_no_primary_mismatched_me.yml +6 -2
- data/spec/support/sdam/rs/primary_wrong_set_name.yml +3 -1
- data/spec/support/sdam/rs/response_from_removed.yml +6 -2
- data/spec/support/sdam/rs/rsother_discovered.yml +6 -2
- data/spec/support/sdam/rs/sec_not_auth.yml +6 -2
- data/spec/support/sdam/rs/secondary_mismatched_me.yml +26 -37
- data/spec/support/sdam/rs/secondary_wrong_set_name.yml +3 -1
- data/spec/support/sdam/rs/secondary_wrong_set_name_with_primary.yml +6 -2
- data/spec/support/sdam/rs/setversion_without_electionid.yml +6 -2
- data/spec/support/sdam/rs/stepdown_change_set_name.yml +6 -2
- data/spec/support/sdam/rs/too_new.yml +41 -0
- data/spec/support/sdam/rs/too_old.yml +39 -0
- data/spec/support/sdam/rs/unexpected_mongos.yml +3 -1
- data/spec/support/sdam/rs/use_setversion_without_electionid.yml +9 -3
- data/spec/support/sdam/rs/wrong_set_name.yml +3 -1
- data/spec/support/server_discovery_and_monitoring.rb +13 -0
- data/spec/support/shared/session.rb +10 -30
- metadata +10 -2
- metadata.gz.sig +0 -0
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA1:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: 22155206427257fef9e634311719afb58b03f76c
         | 
| 4 | 
            +
              data.tar.gz: c156ef4a3569277ad0c398455d7983c3e2475051
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: 4252e5a66f31ee3ba496bd573b37ee08f0dd513b3d1e1b154da01c7d34dc19714fc929de7454cc4ea0415fbb44312a8b1c29cf06c1cfb20adee72e97cd917443
         | 
| 7 | 
            +
              data.tar.gz: efb7c93290353223cfc910a383b0a0edd9f2d0cc3b6405389256f48fe1dd1ed3647449db8d07663300303ba07a25a038f46d4c2ee5b1bdc0e804890e73b698b6
         | 
    
        checksums.yaml.gz.sig
    CHANGED
    
    | Binary file | 
    
        data.tar.gz.sig
    CHANGED
    
    | Binary file | 
    
        data/README.md
    CHANGED
    
    | @@ -45,6 +45,8 @@ Running Tests | |
| 45 45 |  | 
| 46 46 | 
             
            The driver uses RSpec as it's primary testing tool. To run all tests simple run `rspec`.
         | 
| 47 47 |  | 
| 48 | 
            +
            If you need to run the tests without making any external connections, set the ENV variable EXTERNAL_DISABLED to 'true'.
         | 
| 49 | 
            +
             | 
| 48 50 | 
             
            To run a test at a specific location (where `42` is the line number), use:
         | 
| 49 51 |  | 
| 50 52 | 
             
                rspec path/to/spec.rb:42
         | 
    
        data/Rakefile
    CHANGED
    
    | @@ -15,7 +15,10 @@ Bundler.require(*default_groups) | |
| 15 15 |  | 
| 16 16 | 
             
            require 'rspec/core/rake_task'
         | 
| 17 17 |  | 
| 18 | 
            -
            RSpec::Core::RakeTask.new(:spec)
         | 
| 18 | 
            +
            RSpec::Core::RakeTask.new(:spec) do |t|
         | 
| 19 | 
            +
              t.rspec_opts = "--profile 5" if ENV['CI']
         | 
| 20 | 
            +
            end
         | 
| 21 | 
            +
             | 
| 19 22 | 
             
            task :default => :spec
         | 
| 20 23 |  | 
| 21 24 | 
             
            namespace :spec do
         | 
    
        data/lib/mongo/address.rb
    CHANGED
    
    | @@ -185,7 +185,8 @@ module Mongo | |
| 185 185 | 
             
                  error = nil
         | 
| 186 186 | 
             
                  ::Socket.getaddrinfo(host, nil, family, ::Socket::SOCK_STREAM).each do |info|
         | 
| 187 187 | 
             
                    begin
         | 
| 188 | 
            -
                       | 
| 188 | 
            +
                      _host = (host == LOCALHOST) ? info[3] : host
         | 
| 189 | 
            +
                      res = FAMILY_MAP[info[4]].new(_host, port, host)
         | 
| 189 190 | 
             
                      res.socket(connect_timeout, ssl_options).connect!(connect_timeout).close
         | 
| 190 191 | 
             
                      return res
         | 
| 191 192 | 
             
                    rescue IOError, SystemCallError, Error::SocketTimeoutError, Error::SocketError => e
         | 
    
        data/lib/mongo/client.rb
    CHANGED
    
    | @@ -96,8 +96,6 @@ module Mongo | |
| 96 96 | 
             
                # Delegate subscription to monitoring.
         | 
| 97 97 | 
             
                def_delegators :@monitoring, :subscribe, :unsubscribe
         | 
| 98 98 |  | 
| 99 | 
            -
                def_delegators :@cluster, :logical_session_timeout
         | 
| 100 | 
            -
             | 
| 101 99 | 
             
                # Determine if this client is equivalent to another object.
         | 
| 102 100 | 
             
                #
         | 
| 103 101 | 
             
                # @example Check client equality.
         | 
| @@ -249,32 +247,14 @@ module Mongo | |
| 249 247 | 
             
                # @since 2.0.0
         | 
| 250 248 | 
             
                def initialize(addresses_or_uri, options = Options::Redacted.new)
         | 
| 251 249 | 
             
                  @monitoring = Monitoring.new(options)
         | 
| 252 | 
            -
                  Session::SessionPool.create(self)
         | 
| 253 250 | 
             
                  if addresses_or_uri.is_a?(::String)
         | 
| 254 251 | 
             
                    create_from_uri(addresses_or_uri, validate_options!(options))
         | 
| 255 252 | 
             
                  else
         | 
| 256 253 | 
             
                    create_from_addresses(addresses_or_uri, validate_options!(options))
         | 
| 257 254 | 
             
                  end
         | 
| 258 | 
            -
                  ObjectSpace.define_finalizer(self, self.class.finalize(@session_pool))
         | 
| 259 255 | 
             
                  yield(self) if block_given?
         | 
| 260 256 | 
             
                end
         | 
| 261 257 |  | 
| 262 | 
            -
                # Finalize the client for garbage collection. Ends all sessions in the session pool.
         | 
| 263 | 
            -
                #
         | 
| 264 | 
            -
                # @example Finalize the client.
         | 
| 265 | 
            -
                #   Client.finalize(session_pool)
         | 
| 266 | 
            -
                #
         | 
| 267 | 
            -
                # @param [ Session::SessionPool ] session_pool The session pool.
         | 
| 268 | 
            -
                #
         | 
| 269 | 
            -
                # @return [ Proc ] The Finalizer.
         | 
| 270 | 
            -
                #
         | 
| 271 | 
            -
                # @since 2.5.0
         | 
| 272 | 
            -
                def self.finalize(session_pool)
         | 
| 273 | 
            -
                  proc do
         | 
| 274 | 
            -
                    begin; session_pool.end_sessions; rescue; end
         | 
| 275 | 
            -
                  end
         | 
| 276 | 
            -
                end
         | 
| 277 | 
            -
             | 
| 278 258 | 
             
                # Get an inspection of the client as a string.
         | 
| 279 259 | 
             
                #
         | 
| 280 260 | 
             
                # @example Inspect the client.
         | 
| @@ -345,7 +325,6 @@ module Mongo | |
| 345 325 | 
             
                    opts = validate_options!(new_options)
         | 
| 346 326 | 
             
                    client.options.update(opts)
         | 
| 347 327 | 
             
                    Database.create(client)
         | 
| 348 | 
            -
                    Session::SessionPool.create(client)
         | 
| 349 328 | 
             
                    # We can't use the same cluster if some options that would affect it
         | 
| 350 329 | 
             
                    # have changed.
         | 
| 351 330 | 
             
                    if cluster_modifying?(opts)
         | 
| @@ -445,7 +424,7 @@ module Mongo | |
| 445 424 | 
             
                # Start a session.
         | 
| 446 425 | 
             
                #
         | 
| 447 426 | 
             
                # @example Start a session.
         | 
| 448 | 
            -
                #   client.start_session
         | 
| 427 | 
            +
                #   client.start_session(causal_consistency: true)
         | 
| 449 428 | 
             
                #
         | 
| 450 429 | 
             
                # @param [ Hash ] options The session options.
         | 
| 451 430 | 
             
                #
         | 
| @@ -456,42 +435,18 @@ module Mongo | |
| 456 435 | 
             
                #
         | 
| 457 436 | 
             
                # @since 2.5.0
         | 
| 458 437 | 
             
                def start_session(options = {})
         | 
| 459 | 
            -
                   | 
| 460 | 
            -
                    raise Error::InvalidSession.new(Session::SESSIONS_NOT_SUPPORTED)
         | 
| 461 | 
            -
                  end
         | 
| 462 | 
            -
                  Session.new(@session_pool.checkout, self, options)
         | 
| 438 | 
            +
                  cluster.send(:get_session, options.merge(implicit: false)) ||
         | 
| 439 | 
            +
                    (raise Error::InvalidSession.new(Session::SESSIONS_NOT_SUPPORTED))
         | 
| 463 440 | 
             
                end
         | 
| 464 441 |  | 
| 465 442 | 
             
                private
         | 
| 466 443 |  | 
| 467 444 | 
             
                def get_session(options = {})
         | 
| 468 | 
            -
                   | 
| 469 | 
            -
                    options[:session].validate!(self)
         | 
| 470 | 
            -
                    options[:session]
         | 
| 471 | 
            -
                  elsif sessions_supported?
         | 
| 472 | 
            -
                    Session.new(@session_pool.checkout, self, options.merge(implicit: true))
         | 
| 473 | 
            -
                  end
         | 
| 474 | 
            -
                end
         | 
| 475 | 
            -
             | 
| 476 | 
            -
                def with_session(options = {})
         | 
| 477 | 
            -
                  if options[:session]
         | 
| 478 | 
            -
                    options[:session].validate!(self)
         | 
| 479 | 
            -
                    yield(options[:session])
         | 
| 480 | 
            -
                  elsif sessions_supported?
         | 
| 481 | 
            -
                    @session_pool.with_session do |server_session|
         | 
| 482 | 
            -
                      yield(Session.new(server_session, self, options))
         | 
| 483 | 
            -
                    end
         | 
| 484 | 
            -
                  else
         | 
| 485 | 
            -
                    yield
         | 
| 486 | 
            -
                  end
         | 
| 445 | 
            +
                  cluster.send(:get_session, options)
         | 
| 487 446 | 
             
                end
         | 
| 488 447 |  | 
| 489 | 
            -
                def  | 
| 490 | 
            -
                   | 
| 491 | 
            -
                    ServerSelector.get(mode: :primary_preferred).select_server(cluster)
         | 
| 492 | 
            -
                  end
         | 
| 493 | 
            -
                  !!logical_session_timeout
         | 
| 494 | 
            -
                rescue Error::NoServerAvailable
         | 
| 448 | 
            +
                def with_session(options = {}, &block)
         | 
| 449 | 
            +
                  cluster.send(:with_session, options, &block)
         | 
| 495 450 | 
             
                end
         | 
| 496 451 |  | 
| 497 452 | 
             
                def create_from_addresses(addresses, opts = Options::Redacted.new)
         | 
    
        data/lib/mongo/cluster.rb
    CHANGED
    
    | @@ -75,6 +75,11 @@ module Mongo | |
| 75 75 | 
             
                # @since 2.5.0
         | 
| 76 76 | 
             
                attr_reader :cluster_time
         | 
| 77 77 |  | 
| 78 | 
            +
                # @private
         | 
| 79 | 
            +
                #
         | 
| 80 | 
            +
                # @since 2.5.1
         | 
| 81 | 
            +
                attr_reader :session_pool
         | 
| 82 | 
            +
             | 
| 78 83 | 
             
                def_delegators :topology, :replica_set?, :replica_set_name, :sharded?,
         | 
| 79 84 | 
             
                               :single?, :unknown?, :member_discovered
         | 
| 80 85 | 
             
                def_delegators :@cursor_reaper, :register_cursor, :schedule_kill_cursor, :unregister_cursor
         | 
| @@ -173,6 +178,7 @@ module Mongo | |
| 173 178 | 
             
                  @cluster_time = nil
         | 
| 174 179 | 
             
                  @cluster_time_lock = Mutex.new
         | 
| 175 180 | 
             
                  @topology = Topology.initial(seeds, monitoring, options)
         | 
| 181 | 
            +
                  Session::SessionPool.create(self)
         | 
| 176 182 |  | 
| 177 183 | 
             
                  publish_sdam_event(
         | 
| 178 184 | 
             
                    Monitoring::TOPOLOGY_OPENING,
         | 
| @@ -195,7 +201,7 @@ module Mongo | |
| 195 201 | 
             
                  @periodic_executor = PeriodicExecutor.new(@cursor_reaper, @socket_reaper)
         | 
| 196 202 | 
             
                  @periodic_executor.run!
         | 
| 197 203 |  | 
| 198 | 
            -
                  ObjectSpace.define_finalizer(self, self.class.finalize(pools, @periodic_executor))
         | 
| 204 | 
            +
                  ObjectSpace.define_finalizer(self, self.class.finalize(pools, @periodic_executor, @session_pool))
         | 
| 199 205 | 
             
                end
         | 
| 200 206 |  | 
| 201 207 | 
             
                # Finalize the cluster for garbage collection. Disconnects all the scoped
         | 
| @@ -204,14 +210,16 @@ module Mongo | |
| 204 210 | 
             
                # @example Finalize the cluster.
         | 
| 205 211 | 
             
                #   Cluster.finalize(pools)
         | 
| 206 212 | 
             
                #
         | 
| 207 | 
            -
                # @param [ Hash<Address, Server::ConnectionPool> ] pools The connection
         | 
| 208 | 
            -
                # | 
| 213 | 
            +
                # @param [ Hash<Address, Server::ConnectionPool> ] pools The connection pools.
         | 
| 214 | 
            +
                # @param [ PeriodicExecutor ] periodic_executor The periodic executor.
         | 
| 215 | 
            +
                # @param [ SessionPool ] session_pool The session pool.
         | 
| 209 216 | 
             
                #
         | 
| 210 217 | 
             
                # @return [ Proc ] The Finalizer.
         | 
| 211 218 | 
             
                #
         | 
| 212 219 | 
             
                # @since 2.2.0
         | 
| 213 | 
            -
                def self.finalize(pools, periodic_executor)
         | 
| 220 | 
            +
                def self.finalize(pools, periodic_executor, session_pool)
         | 
| 214 221 | 
             
                  proc do
         | 
| 222 | 
            +
                    session_pool.end_sessions
         | 
| 215 223 | 
             
                    periodic_executor.stop!
         | 
| 216 224 | 
             
                    pools.values.each do |pool|
         | 
| 217 225 | 
             
                      pool.disconnect!
         | 
| @@ -495,6 +503,28 @@ module Mongo | |
| 495 503 |  | 
| 496 504 | 
             
                private
         | 
| 497 505 |  | 
| 506 | 
            +
                def get_session(options = {})
         | 
| 507 | 
            +
                  return options[:session].validate!(self) if options[:session]
         | 
| 508 | 
            +
                  if sessions_supported?
         | 
| 509 | 
            +
                    Session.new(@session_pool.checkout, self, { implicit: true }.merge(options))
         | 
| 510 | 
            +
                  end
         | 
| 511 | 
            +
                end
         | 
| 512 | 
            +
             | 
| 513 | 
            +
                def with_session(options = {})
         | 
| 514 | 
            +
                  session = get_session(options)
         | 
| 515 | 
            +
                  yield(session)
         | 
| 516 | 
            +
                ensure
         | 
| 517 | 
            +
                  session.end_session if (session && session.implicit?)
         | 
| 518 | 
            +
                end
         | 
| 519 | 
            +
             | 
| 520 | 
            +
                def sessions_supported?
         | 
| 521 | 
            +
                  if servers.empty? && !topology.single?
         | 
| 522 | 
            +
                    ServerSelector.get(mode: :primary_preferred).select_server(self)
         | 
| 523 | 
            +
                  end
         | 
| 524 | 
            +
                  !!logical_session_timeout
         | 
| 525 | 
            +
                rescue Error::NoServerAvailable
         | 
| 526 | 
            +
                end
         | 
| 527 | 
            +
             | 
| 498 528 | 
             
                def direct_connection?(address)
         | 
| 499 529 | 
             
                  address.seed == @topology.seed
         | 
| 500 530 | 
             
                end
         | 
| @@ -29,7 +29,7 @@ module Mongo | |
| 29 29 | 
             
                  # @example Initialize the socket reaper.
         | 
| 30 30 | 
             
                  #   SocketReaper.new(cluster)
         | 
| 31 31 | 
             
                  #
         | 
| 32 | 
            -
                  # @ | 
| 32 | 
            +
                  # @param [ Mongo::Cluster ] cluster The cluster whose pools' stale sockets
         | 
| 33 33 | 
             
                  #  need to be reaped at regular intervals.
         | 
| 34 34 | 
             
                  #
         | 
| 35 35 | 
             
                  # @since 2.5.0
         | 
| @@ -217,7 +217,9 @@ module Mongo | |
| 217 217 | 
             
                    # @since 2.0.6
         | 
| 218 218 | 
             
                    def remove_server?(description, server)
         | 
| 219 219 | 
             
                      remove_self?(description, server) ||
         | 
| 220 | 
            -
                        (member_of_this_set?(description) && | 
| 220 | 
            +
                        (member_of_this_set?(description) &&
         | 
| 221 | 
            +
                            !description.servers.empty? &&
         | 
| 222 | 
            +
                              !description.lists_server?(server))
         | 
| 221 223 | 
             
                    end
         | 
| 222 224 |  | 
| 223 225 | 
             
                    # A replica set topology is not sharded.
         | 
    
        data/lib/mongo/collection.rb
    CHANGED
    
    | @@ -410,23 +410,23 @@ module Mongo | |
| 410 410 | 
             
                #   collection.insert_one({ name: 'test' })
         | 
| 411 411 | 
             
                #
         | 
| 412 412 | 
             
                # @param [ Hash ] document The document to insert.
         | 
| 413 | 
            -
                # @param [ Hash ]  | 
| 413 | 
            +
                # @param [ Hash ] opts The insert options.
         | 
| 414 414 | 
             
                #
         | 
| 415 | 
            -
                # @option  | 
| 415 | 
            +
                # @option opts [ Session ] :session The session to use for the operation.
         | 
| 416 416 | 
             
                #
         | 
| 417 417 | 
             
                # @return [ Result ] The database response wrapper.
         | 
| 418 418 | 
             
                #
         | 
| 419 419 | 
             
                # @since 2.0.0
         | 
| 420 | 
            -
                def insert_one(document,  | 
| 421 | 
            -
                  client.send(:with_session,  | 
| 420 | 
            +
                def insert_one(document, opts = {})
         | 
| 421 | 
            +
                  client.send(:with_session, opts) do |session|
         | 
| 422 422 | 
             
                    write_with_retry(session, write_concern) do |server, txn_num|
         | 
| 423 423 | 
             
                      Operation::Write::Insert.new(
         | 
| 424 424 | 
             
                          :documents => [ document ],
         | 
| 425 425 | 
             
                          :db_name => database.name,
         | 
| 426 426 | 
             
                          :coll_name => name,
         | 
| 427 427 | 
             
                          :write_concern => write_concern,
         | 
| 428 | 
            -
                          :bypass_document_validation => !! | 
| 429 | 
            -
                          :options =>  | 
| 428 | 
            +
                          :bypass_document_validation => !!opts[:bypass_document_validation],
         | 
| 429 | 
            +
                          :options => opts,
         | 
| 430 430 | 
             
                          :id_generator => client.options[:id_generator],
         | 
| 431 431 | 
             
                          :session => session,
         | 
| 432 432 | 
             
                          :txn_num => txn_num
         | 
| @@ -199,10 +199,8 @@ module Mongo | |
| 199 199 |  | 
| 200 200 | 
             
                  def view; self; end
         | 
| 201 201 |  | 
| 202 | 
            -
                  def with_session(opts = {})
         | 
| 203 | 
            -
                    client.send(:with_session, @options.merge(opts)) | 
| 204 | 
            -
                      yield(session)
         | 
| 205 | 
            -
                    end
         | 
| 202 | 
            +
                  def with_session(opts = {}, &block)
         | 
| 203 | 
            +
                    client.send(:with_session, @options.merge(opts), &block)
         | 
| 206 204 | 
             
                  end
         | 
| 207 205 | 
             
                end
         | 
| 208 206 | 
             
              end
         | 
    
        data/lib/mongo/cursor.rb
    CHANGED
    
    | @@ -69,7 +69,8 @@ module Mongo | |
| 69 69 | 
             
                  ObjectSpace.define_finalizer(self, self.class.finalize(result.cursor_id,
         | 
| 70 70 | 
             
                                                                         cluster,
         | 
| 71 71 | 
             
                                                                         kill_cursors_op_spec,
         | 
| 72 | 
            -
                                                                         server | 
| 72 | 
            +
                                                                         server,
         | 
| 73 | 
            +
                                                                         @session))
         | 
| 73 74 | 
             
                end
         | 
| 74 75 |  | 
| 75 76 |  | 
| @@ -87,8 +88,11 @@ module Mongo | |
| 87 88 | 
             
                # @return [ Proc ] The Finalizer.
         | 
| 88 89 | 
             
                #
         | 
| 89 90 | 
             
                # @since 2.3.0
         | 
| 90 | 
            -
                def self.finalize(cursor_id, cluster, op_spec, server)
         | 
| 91 | 
            -
                  proc  | 
| 91 | 
            +
                def self.finalize(cursor_id, cluster, op_spec, server, session)
         | 
| 92 | 
            +
                  proc do
         | 
| 93 | 
            +
                    cluster.schedule_kill_cursor(cursor_id, op_spec, server)
         | 
| 94 | 
            +
                    session.end_session if session && session.implicit?
         | 
| 95 | 
            +
                  end
         | 
| 92 96 | 
             
                end
         | 
| 93 97 |  | 
| 94 98 | 
             
                # Get a human-readable string representation of +Cursor+.
         | 
| @@ -219,7 +223,7 @@ module Mongo | |
| 219 223 | 
             
                end
         | 
| 220 224 |  | 
| 221 225 | 
             
                def end_session
         | 
| 222 | 
            -
                  @session. | 
| 226 | 
            +
                  @session.end_session if @session && @session.implicit?
         | 
| 223 227 | 
             
                end
         | 
| 224 228 |  | 
| 225 229 | 
             
                def kill_cursors_operation
         | 
| @@ -251,6 +255,7 @@ module Mongo | |
| 251 255 | 
             
                  @coll_name ||= result.namespace.sub("#{database.name}.", '') if result.namespace
         | 
| 252 256 | 
             
                  unregister if result.cursor_id == 0
         | 
| 253 257 | 
             
                  @cursor_id = result.cursor_id
         | 
| 258 | 
            +
                  end_session if !more?
         | 
| 254 259 | 
             
                  result.documents
         | 
| 255 260 | 
             
                end
         | 
| 256 261 |  | 
    
        data/lib/mongo/error.rb
    CHANGED
    
    
| @@ -58,7 +58,7 @@ module Mongo | |
| 58 58 | 
             
                        apply_session_id!(selector)
         | 
| 59 59 | 
             
                        apply_causal_consistency!(selector, server)
         | 
| 60 60 | 
             
                      end
         | 
| 61 | 
            -
                    elsif session && !session. | 
| 61 | 
            +
                    elsif session && !session.implicit?
         | 
| 62 62 | 
             
                      apply_cluster_time!(selector, server)
         | 
| 63 63 | 
             
                      apply_session_id!(selector)
         | 
| 64 64 | 
             
                      apply_causal_consistency!(selector, server)
         | 
    
        data/lib/mongo/server.rb
    CHANGED
    
    
| @@ -264,7 +264,7 @@ module Mongo | |
| 264 264 | 
             
                  def initialize(address, config = {}, average_round_trip_time = 0)
         | 
| 265 265 | 
             
                    @address = address
         | 
| 266 266 | 
             
                    @config = config
         | 
| 267 | 
            -
                    @features = Features.new(wire_versions, me)
         | 
| 267 | 
            +
                    @features = Features.new(wire_versions, me || @address.to_s)
         | 
| 268 268 | 
             
                    @average_round_trip_time = average_round_trip_time
         | 
| 269 269 | 
             
                  end
         | 
| 270 270 |  | 
| @@ -88,21 +88,27 @@ module Mongo | |
| 88 88 | 
             
                    # @since 2.0.0
         | 
| 89 89 | 
             
                    def initialize(server_wire_versions, address = nil)
         | 
| 90 90 | 
             
                      @server_wire_versions = server_wire_versions
         | 
| 91 | 
            -
                       | 
| 91 | 
            +
                      @address = address
         | 
| 92 92 | 
             
                    end
         | 
| 93 93 |  | 
| 94 | 
            -
                     | 
| 95 | 
            -
             | 
| 96 | 
            -
                     | 
| 97 | 
            -
             | 
| 98 | 
            -
                     | 
| 99 | 
            -
             | 
| 100 | 
            -
             | 
| 101 | 
            -
             | 
| 94 | 
            +
                    # Check that there is an overlap between the driver supported wire version range
         | 
| 95 | 
            +
                    #   and the server wire version range.
         | 
| 96 | 
            +
                    #
         | 
| 97 | 
            +
                    # @example Verify the wire version overlap.
         | 
| 98 | 
            +
                    #   features.check_driver_support!
         | 
| 99 | 
            +
                    #
         | 
| 100 | 
            +
                    # @raise [ Error::UnsupportedFeatures ] If the wire version range is not covered
         | 
| 101 | 
            +
                    #   by the driver.
         | 
| 102 | 
            +
                    #
         | 
| 103 | 
            +
                    # @since 2.5.1
         | 
| 104 | 
            +
                    def check_driver_support!
         | 
| 105 | 
            +
                      if DRIVER_WIRE_VERSIONS.min > @server_wire_versions.max
         | 
| 106 | 
            +
                        raise Error::UnsupportedFeatures.new(SERVER_TOO_OLD % [@address,
         | 
| 107 | 
            +
                                                                               @server_wire_versions.max,
         | 
| 102 108 | 
             
                                                                               DRIVER_WIRE_VERSIONS.min])
         | 
| 103 | 
            -
                      elsif DRIVER_WIRE_VERSIONS.max < server_wire_versions.min
         | 
| 104 | 
            -
                        raise Error::UnsupportedFeatures.new(DRIVER_TOO_OLD % [address,
         | 
| 105 | 
            -
                                                                               server_wire_versions.min,
         | 
| 109 | 
            +
                      elsif DRIVER_WIRE_VERSIONS.max < @server_wire_versions.min
         | 
| 110 | 
            +
                        raise Error::UnsupportedFeatures.new(DRIVER_TOO_OLD % [@address,
         | 
| 111 | 
            +
                                                                               @server_wire_versions.min,
         | 
| 106 112 | 
             
                                                                               DRIVER_WIRE_VERSIONS.max])
         | 
| 107 113 | 
             
                      end
         | 
| 108 114 | 
             
                    end
         | 
| @@ -105,8 +105,12 @@ module Mongo | |
| 105 105 | 
             
                        # There is no point pinging a standalone as the subsequent scan is
         | 
| 106 106 | 
             
                        # not going to change anything about the cluster.
         | 
| 107 107 | 
             
                        if ping && !cluster.single?
         | 
| 108 | 
            -
                           | 
| 108 | 
            +
                          if server.connectable?
         | 
| 109 | 
            +
                            server.check_driver_support!
         | 
| 110 | 
            +
                            return server
         | 
| 111 | 
            +
                          end
         | 
| 109 112 | 
             
                        else
         | 
| 113 | 
            +
                          server.check_driver_support!
         | 
| 110 114 | 
             
                          return server
         | 
| 111 115 | 
             
                        end
         | 
| 112 116 | 
             
                      end
         | 
    
        data/lib/mongo/session.rb
    CHANGED
    
    | @@ -17,7 +17,7 @@ require 'mongo/session/server_session' | |
| 17 17 |  | 
| 18 18 | 
             
            module Mongo
         | 
| 19 19 |  | 
| 20 | 
            -
              # A logical  | 
| 20 | 
            +
              # A logical session representing a set of sequential operations executed
         | 
| 21 21 | 
             
              #   by an application that are related in some way.
         | 
| 22 22 | 
             
              #
         | 
| 23 23 | 
             
              # @since 2.5.0
         | 
| @@ -29,10 +29,10 @@ module Mongo | |
| 29 29 | 
             
                # @since 2.5.0
         | 
| 30 30 | 
             
                attr_reader :options
         | 
| 31 31 |  | 
| 32 | 
            -
                # Get the  | 
| 32 | 
            +
                # Get the cluster through which this session was created.
         | 
| 33 33 | 
             
                #
         | 
| 34 | 
            -
                # @since 2.5. | 
| 35 | 
            -
                attr_reader : | 
| 34 | 
            +
                # @since 2.5.1
         | 
| 35 | 
            +
                attr_reader :cluster
         | 
| 36 36 |  | 
| 37 37 | 
             
                # The cluster time for this session.
         | 
| 38 38 | 
             
                #
         | 
| @@ -44,14 +44,13 @@ module Mongo | |
| 44 44 | 
             
                # @since 2.5.0
         | 
| 45 45 | 
             
                attr_reader :operation_time
         | 
| 46 46 |  | 
| 47 | 
            -
                 | 
| 48 | 
            -
             | 
| 49 | 
            -
                # Error message describing that the session was attempted to be used by a client different from the
         | 
| 50 | 
            -
                # one it was originally associated with.
         | 
| 47 | 
            +
                # Error message indicating that the session was retrieved from a client with a different cluster than that of the
         | 
| 48 | 
            +
                # client through which it is currently being used.
         | 
| 51 49 | 
             
                #
         | 
| 52 50 | 
             
                # @since 2.5.0
         | 
| 53 | 
            -
                MISMATCHED_CLUSTER_ERROR_MSG = 'The client used to create this session does not match that  | 
| 54 | 
            -
                    ' | 
| 51 | 
            +
                MISMATCHED_CLUSTER_ERROR_MSG = 'The configuration of the client used to create this session does not match that ' +
         | 
| 52 | 
            +
                    'of the client owning this operation. Please only use this session for operations through its parent ' +
         | 
| 53 | 
            +
                    'client.'.freeze
         | 
| 55 54 |  | 
| 56 55 | 
             
                # Error message describing that the session cannot be used because it has already been ended.
         | 
| 57 56 | 
             
                #
         | 
| @@ -66,16 +65,16 @@ module Mongo | |
| 66 65 | 
             
                # Initialize a Session.
         | 
| 67 66 | 
             
                #
         | 
| 68 67 | 
             
                # @example
         | 
| 69 | 
            -
                #   Session.new(server_session,  | 
| 68 | 
            +
                #   Session.new(server_session, cluster, options)
         | 
| 70 69 | 
             
                #
         | 
| 71 | 
            -
                # @param [ ServerSession ] server_session The server session this  | 
| 72 | 
            -
                # @param [  | 
| 70 | 
            +
                # @param [ ServerSession ] server_session The server session this session is associated with.
         | 
| 71 | 
            +
                # @param [ Cluster ] cluster The cluster through which this session is created.
         | 
| 73 72 | 
             
                # @param [ Hash ] options The options for this session.
         | 
| 74 73 | 
             
                #
         | 
| 75 74 | 
             
                # @since 2.5.0
         | 
| 76 | 
            -
                def initialize(server_session,  | 
| 75 | 
            +
                def initialize(server_session, cluster, options = {})
         | 
| 77 76 | 
             
                  @server_session = server_session
         | 
| 78 | 
            -
                  @ | 
| 77 | 
            +
                  @cluster = cluster
         | 
| 79 78 | 
             
                  @options = options.dup.freeze
         | 
| 80 79 | 
             
                  @cluster_time = nil
         | 
| 81 80 | 
             
                end
         | 
| @@ -101,26 +100,13 @@ module Mongo | |
| 101 100 | 
             
                #
         | 
| 102 101 | 
             
                # @since 2.5.0
         | 
| 103 102 | 
             
                def end_session
         | 
| 104 | 
            -
                  if !ended? && @ | 
| 105 | 
            -
                    @ | 
| 106 | 
            -
                    nil
         | 
| 103 | 
            +
                  if !ended? && @cluster
         | 
| 104 | 
            +
                    @cluster.session_pool.checkin(@server_session)
         | 
| 107 105 | 
             
                  end
         | 
| 108 106 | 
             
                ensure
         | 
| 109 107 | 
             
                  @server_session = nil
         | 
| 110 108 | 
             
                end
         | 
| 111 109 |  | 
| 112 | 
            -
                # End this session if it's an implicit session.
         | 
| 113 | 
            -
                #
         | 
| 114 | 
            -
                # @example
         | 
| 115 | 
            -
                #   session.end_implicit_session
         | 
| 116 | 
            -
                #
         | 
| 117 | 
            -
                # @return [ nil ] Always nil.
         | 
| 118 | 
            -
                #
         | 
| 119 | 
            -
                # @since 2.5.0
         | 
| 120 | 
            -
                def end_implicit_session
         | 
| 121 | 
            -
                  end_session if implicit_session?
         | 
| 122 | 
            -
                end
         | 
| 123 | 
            -
             | 
| 124 110 | 
             
                # Whether this session has ended.
         | 
| 125 111 | 
             
                #
         | 
| 126 112 | 
             
                # @example
         | 
| @@ -148,18 +134,19 @@ module Mongo | |
| 148 134 | 
             
                # Validate the session.
         | 
| 149 135 | 
             
                #
         | 
| 150 136 | 
             
                # @example
         | 
| 151 | 
            -
                #   session.validate!( | 
| 137 | 
            +
                #   session.validate!(cluster)
         | 
| 152 138 | 
             
                #
         | 
| 153 | 
            -
                # @param [  | 
| 139 | 
            +
                # @param [ Cluster ] cluster The cluster the session is attempted to be used with.
         | 
| 154 140 | 
             
                #
         | 
| 155 141 | 
             
                # @return [ nil ] nil if the session is valid.
         | 
| 156 142 | 
             
                #
         | 
| 157 143 | 
             
                # @raise [ Mongo::Error::InvalidSession ] Raise error if the session is not valid.
         | 
| 158 144 | 
             
                #
         | 
| 159 145 | 
             
                # @since 2.5.0
         | 
| 160 | 
            -
                def validate!( | 
| 161 | 
            -
                   | 
| 146 | 
            +
                def validate!(cluster)
         | 
| 147 | 
            +
                  check_matching_cluster!(cluster)
         | 
| 162 148 | 
             
                  check_if_ended!
         | 
| 149 | 
            +
                  self
         | 
| 163 150 | 
             
                end
         | 
| 164 151 |  | 
| 165 152 | 
             
                # Process a response from the server that used this session.
         | 
| @@ -173,7 +160,7 @@ module Mongo | |
| 173 160 | 
             
                #
         | 
| 174 161 | 
             
                # @since 2.5.0
         | 
| 175 162 | 
             
                def process(result)
         | 
| 176 | 
            -
                  unless  | 
| 163 | 
            +
                  unless implicit?
         | 
| 177 164 | 
             
                    set_operation_time(result)
         | 
| 178 165 | 
             
                    set_cluster_time(result)
         | 
| 179 166 | 
             
                  end
         | 
| @@ -229,7 +216,7 @@ module Mongo | |
| 229 216 | 
             
                #
         | 
| 230 217 | 
             
                # @since 2.5.0
         | 
| 231 218 | 
             
                def retry_writes?
         | 
| 232 | 
            -
                  !! | 
| 219 | 
            +
                  !!cluster.options[:retry_writes] && (cluster.replica_set? || cluster.sharded?)
         | 
| 233 220 | 
             
                end
         | 
| 234 221 |  | 
| 235 222 | 
             
                # Get the session id.
         | 
| @@ -247,7 +234,7 @@ module Mongo | |
| 247 234 | 
             
                # Increment and return the next transaction number.
         | 
| 248 235 | 
             
                #
         | 
| 249 236 | 
             
                # @example Get the next transaction number.
         | 
| 250 | 
            -
                #    | 
| 237 | 
            +
                #   session.next_txn_num
         | 
| 251 238 | 
             
                #
         | 
| 252 239 | 
             
                # @return [ Integer ] The next transaction number.
         | 
| 253 240 | 
             
                #
         | 
| @@ -256,6 +243,18 @@ module Mongo | |
| 256 243 | 
             
                  @server_session.next_txn_num if @server_session
         | 
| 257 244 | 
             
                end
         | 
| 258 245 |  | 
| 246 | 
            +
                # Is this session an implicit one (not user-created).
         | 
| 247 | 
            +
                #
         | 
| 248 | 
            +
                # @example Is the session implicit?
         | 
| 249 | 
            +
                #   session.implicit?
         | 
| 250 | 
            +
                #
         | 
| 251 | 
            +
                # @return [ true, false ] Whether this session is implicit.
         | 
| 252 | 
            +
                #
         | 
| 253 | 
            +
                # @since 2.5.1
         | 
| 254 | 
            +
                def implicit?
         | 
| 255 | 
            +
                  @implicit_session ||= !!(@options.key?(:implicit) && @options[:implicit] == true)
         | 
| 256 | 
            +
                end
         | 
| 257 | 
            +
             | 
| 259 258 | 
             
                private
         | 
| 260 259 |  | 
| 261 260 | 
             
                def causal_consistency_doc(read_concern)
         | 
| @@ -274,10 +273,6 @@ module Mongo | |
| 274 273 | 
             
                                           end)
         | 
| 275 274 | 
             
                end
         | 
| 276 275 |  | 
| 277 | 
            -
                def implicit_session?
         | 
| 278 | 
            -
                  @implicit_session ||= !!(@options.key?(:implicit) && @options[:implicit] == true)
         | 
| 279 | 
            -
                end
         | 
| 280 | 
            -
             | 
| 281 276 | 
             
                def set_operation_time(result)
         | 
| 282 277 | 
             
                  if result && result.operation_time
         | 
| 283 278 | 
             
                    @operation_time = result.operation_time
         | 
| @@ -298,8 +293,8 @@ module Mongo | |
| 298 293 | 
             
                  raise Mongo::Error::InvalidSession.new(SESSION_ENDED_ERROR_MSG) if ended?
         | 
| 299 294 | 
             
                end
         | 
| 300 295 |  | 
| 301 | 
            -
                def  | 
| 302 | 
            -
                  if @ | 
| 296 | 
            +
                def check_matching_cluster!(cluster)
         | 
| 297 | 
            +
                  if @cluster != cluster
         | 
| 303 298 | 
             
                    raise Mongo::Error::InvalidSession.new(MISMATCHED_CLUSTER_ERROR_MSG)
         | 
| 304 299 | 
             
                  end
         | 
| 305 300 | 
             
                end
         |