diff --git a/.gitignore b/.gitignore index e117d19..fa2469c 100644 --- a/.gitignore +++ b/.gitignore @@ -18,3 +18,4 @@ benchmark *.log test/load/unicorn/unicorn.rb test/load/thin/config.yml +.rvmrc \ No newline at end of file diff --git a/lib/mongo/connection.rb b/lib/mongo/connection.rb index 318c917..b338a1e 100644 --- a/lib/mongo/connection.rb +++ b/lib/mongo/connection.rb @@ -38,7 +38,7 @@ module Mongo attr_reader :logger, :size, :auths, :primary, :safe, :host_to_try, :pool_size, :connect_timeout, :pool_timeout, - :primary_pool, :socket_class + :primary_pool, :socket_class, :op_timeout # Create a connection to single MongoDB instance. # @@ -52,7 +52,7 @@ module Mongo # Connection#arbiters. This is useful if your application needs to connect manually to nodes other # than the primary. # - # @param [String, Hash] host. + # @param [String, Hash] host # @param [Integer] port specify a port number here if only one host is being specified. # # @option opts [Boolean, Hash] :safe (false) Set the default safe-mode options diff --git a/lib/mongo/db.rb b/lib/mongo/db.rb index e82c2f7..f5613f5 100644 --- a/lib/mongo/db.rb +++ b/lib/mongo/db.rb @@ -332,6 +332,7 @@ module Mongo # @option opts [Boolean] :fsync (false) # @option opts [Integer] :w (nil) # @option opts [Integer] :wtimeout (nil) + # @option opts [Boolean] :j (false) # # @return [Hash] the entire response to getlasterror. # diff --git a/lib/mongo/util/uri_parser.rb b/lib/mongo/util/uri_parser.rb index 51a1602..1fb331f 100644 --- a/lib/mongo/util/uri_parser.rb +++ b/lib/mongo/util/uri_parser.rb @@ -35,36 +35,48 @@ module Mongo MONGODB_URI_SPEC = "mongodb://[username:password@]host1[:port1][,host2[:port2],...[,hostN[:portN]]][/database]" SPEC_ATTRS = [:nodes, :auths] - OPT_ATTRS = [:connect, :replicaset, :slaveok, :safe, :w, :wtimeout, :fsync] + OPT_ATTRS = [:connect, :replicaset, :slaveok, :safe, :w, :wtimeout, :fsync, :journal, :connectTimeoutMS, :socketTimeoutMS, :wtimeoutMS] - OPT_VALID = {:connect => lambda {|arg| ['direct', 'replicaset'].include?(arg)}, - :replicaset => lambda {|arg| arg.length > 0}, - :slaveok => lambda {|arg| ['true', 'false'].include?(arg)}, - :safe => lambda {|arg| ['true', 'false'].include?(arg)}, - :w => lambda {|arg| arg =~ /^\d+$/ }, - :wtimeout => lambda {|arg| arg =~ /^\d+$/ }, - :fsync => lambda {|arg| ['true', 'false'].include?(arg)} + OPT_VALID = {:connect => lambda {|arg| ['direct', 'replicaset'].include?(arg)}, + :replicaset => lambda {|arg| arg.length > 0}, + :slaveok => lambda {|arg| ['true', 'false'].include?(arg)}, + :safe => lambda {|arg| ['true', 'false'].include?(arg)}, + :w => lambda {|arg| arg =~ /^\d+$/ }, + :wtimeout => lambda {|arg| arg =~ /^\d+$/ }, + :fsync => lambda {|arg| ['true', 'false'].include?(arg)}, + :journal => lambda {|arg| ['true', 'false'].include?(arg)}, + :connectTimeoutMS => lambda {|arg| arg =~ /^\d+$/ }, + :socketTimeoutMS => lambda {|arg| arg =~ /^\d+$/ }, + :wtimeoutMS => lambda {|arg| arg =~ /^\d+$/ } } - OPT_ERR = {:connect => "must be 'direct' or 'replicaset'", - :replicaset => "must be a string containing the name of the replica set to connect to", - :slaveok => "must be 'true' or 'false'", - :safe => "must be 'true' or 'false'", - :w => "must be an integer specifying number of nodes to replica to", - :wtimeout => "must be an integer specifying milliseconds", - :fsync => "must be 'true' or 'false'" + OPT_ERR = {:connect => "must be 'direct' or 'replicaset'", + :replicaset => "must be a string containing the name of the replica set to connect to", + :slaveok => "must be 'true' or 'false'", + :safe => "must be 'true' or 'false'", + :w => "must be an integer specifying number of nodes to replica to", + :wtimeout => "must be an integer specifying milliseconds", + :fsync => "must be 'true' or 'false'", + :journal => "must be 'true' or 'false'", + :connectTimeoutMS => "must be an integer specifying milliseconds a connection can take to be opened before timing out", + :socketTimeoutMS => "must be an integer specifying milliseconds a send or receive on a socket can take before timing out", + :wtimeoutMS => "must be an integer specifying milliseconds a send or receive on a socket can take before timing out" } - OPT_CONV = {:connect => lambda {|arg| arg}, - :replicaset => lambda {|arg| arg}, - :slaveok => lambda {|arg| arg == 'true' ? true : false}, - :safe => lambda {|arg| arg == 'true' ? true : false}, - :w => lambda {|arg| arg.to_i}, - :wtimeout => lambda {|arg| arg.to_i}, - :fsync => lambda {|arg| arg == 'true' ? true : false} + OPT_CONV = {:connect => lambda {|arg| arg}, + :replicaset => lambda {|arg| arg}, + :slaveok => lambda {|arg| arg == 'true' ? true : false}, + :safe => lambda {|arg| arg == 'true' ? true : false}, + :w => lambda {|arg| arg.to_i}, + :wtimeout => lambda {|arg| arg.to_i}, + :fsync => lambda {|arg| arg == 'true' ? true : false}, + :journal => lambda {|arg| arg == 'true' ? true : false}, + :connectTimeoutMS => lambda {|arg| arg.to_i }, + :socketTimeoutMS => lambda {|arg| arg.to_i }, + :wtimeoutMS => lambda {|arg| arg.to_i } } - attr_reader :nodes, :auths, :connect, :replicaset, :slaveok, :safe, :w, :wtimeout, :fsync + attr_reader :nodes, :auths, :connect, :replicaset, :slaveok, :safe, :w, :wtimeout, :fsync, :journal, :connectTimeoutMS, :socketTimeoutMS, :wtimeoutMS # Parse a MongoDB URI. This method is used by Connection.from_uri. # Returns an array of nodes and an array of db authorizations, if applicable. @@ -88,15 +100,25 @@ module Mongo def connection_options opts = {} - if (@w || @wtimeout || @fsync) && !@safe - raise MongoArgumentError, "Safe must be true if w, wtimeout, or fsync is specified" + if (@w || @journal || @wtimeout || @fsync || @wtimeoutMS) && !@safe + raise MongoArgumentError, "Safe must be true if w, journal, wtimeoutMS, or fsync is specified" end if @safe - if @w || @wtimeout || @fsync + if @w || @journal || @wtimeout || @fsync || @wtimeoutMS safe_opts = {} safe_opts[:w] = @w if @w - safe_opts[:wtimeout] = @wtimeout if @wtimeout + safe_opts[:j] = @journal if @journal + + if @wtimeout + warn "Using wtimeout in a URI is deprecated, please use wtimeoutMS. It will be removed in v2.0." + safe_opts[:wtimeout] = @wtimeout + end + + if @wtimeoutMS + safe_opts[:wtimeout] = @wtimeoutMS / 1000 + end + safe_opts[:fsync] = @fsync if @fsync else safe_opts = true @@ -104,6 +126,14 @@ module Mongo opts[:safe] = safe_opts end + + if @connectTimeoutMS + opts[:connect_timeout] = @connectTimeoutMS / 1000 + end + + if @socketTimeoutMS + opts[:op_timeout] = @socketTimeoutMS / 1000 + end if @slaveok if @connect == 'direct' diff --git a/test/unit/connection_test.rb b/test/unit/connection_test.rb index dad3d9e..324bfc5 100644 --- a/test/unit/connection_test.rb +++ b/test/unit/connection_test.rb @@ -45,6 +45,28 @@ class ConnectionTest < Test::Unit::TestCase @conn = Connection.from_uri("mongodb://#{host_name}/foo", :connect => false) assert_equal [host_name, 27017], @conn.host_to_try end + + should "set safe options on connection" do + host_name = "localhost" + opts = "safe=true&w=2&wtimeoutMS=10000&fsync=true&journal=true" + @conn = Connection.from_uri("mongodb://#{host_name}/foo?#{opts}", :connect => false) + assert_equal({:w => 2, :wtimeout => 10, :fsync => true, :j => true}, @conn.safe) + end + + should "have wtimeoutMS take precidence over the depricated wtimeout" do + host_name = "localhost" + opts = "safe=true&wtimeout=10&wtimeoutMS=2000" + @conn = Connection.from_uri("mongodb://#{host_name}/foo?#{opts}", :connect => false) + assert_equal({:wtimeout => 2}, @conn.safe) + end + + should "set timeout options on connection" do + host_name = "localhost" + opts = "connectTimeoutMS=1000&socketTimeoutMS=5000" + @conn = Connection.from_uri("mongodb://#{host_name}/foo?#{opts}", :connect => false) + assert_equal 1, @conn.connect_timeout + assert_equal 5, @conn.op_timeout + end should "parse a uri with a hyphen & underscore in the username or password" do @conn = Connection.from_uri("mongodb://hyphen-user_name:p-s_s@localhost:27017/db", :connect => false) diff --git a/test/uri_test.rb b/test/uri_test.rb index 01df2e6..1167986 100644 --- a/test/uri_test.rb +++ b/test/uri_test.rb @@ -78,11 +78,19 @@ class TestThreading < Test::Unit::TestCase end def test_opts_safe - parser = Mongo::URIParser.new('mongodb://localhost:27018?safe=true;w=2;wtimeout=200;fsync=true') + parser = Mongo::URIParser.new('mongodb://localhost:27018?safe=true;w=2;journal=true;wtimeout=200;fsync=true;wtimeoutMS=200') assert parser.safe assert_equal 2, parser.w assert_equal 200, parser.wtimeout assert parser.fsync + assert parser.journal + assert_equal 200, parser.wtimeoutMS + end + + def test_opts_unsafe_timeout + parser = Mongo::URIParser.new('mongodb://localhost:27018?connectTimeoutMS=5000&socketTimeoutMS=10000') + assert_equal 5000, parser.connectTimeoutMS + assert_equal 10000, parser.socketTimeoutMS end def test_opts_replica_set