mongo 1.9.2 → 1.10.0.rc0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (113) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/LICENSE +1 -1
  5. data/README.md +94 -334
  6. data/Rakefile +6 -4
  7. data/VERSION +1 -1
  8. data/bin/mongo_console +13 -6
  9. data/lib/mongo.rb +22 -27
  10. data/lib/mongo/bulk_write_collection_view.rb +352 -0
  11. data/lib/mongo/collection.rb +128 -188
  12. data/lib/mongo/collection_writer.rb +348 -0
  13. data/lib/mongo/connection.rb +19 -0
  14. data/lib/mongo/{util → connection}/node.rb +15 -1
  15. data/lib/mongo/{util → connection}/pool.rb +34 -19
  16. data/lib/mongo/{util → connection}/pool_manager.rb +8 -2
  17. data/lib/mongo/{util → connection}/sharding_pool_manager.rb +1 -1
  18. data/lib/mongo/connection/socket.rb +18 -0
  19. data/lib/mongo/{util → connection/socket}/socket_util.rb +5 -2
  20. data/lib/mongo/{util → connection/socket}/ssl_socket.rb +3 -4
  21. data/lib/mongo/{util → connection/socket}/tcp_socket.rb +25 -15
  22. data/lib/mongo/{util → connection/socket}/unix_socket.rb +6 -4
  23. data/lib/mongo/cursor.rb +113 -47
  24. data/lib/mongo/db.rb +203 -131
  25. data/lib/mongo/{exceptions.rb → exception.rb} +7 -1
  26. data/lib/mongo/functional.rb +19 -0
  27. data/lib/mongo/functional/authentication.rb +303 -0
  28. data/lib/mongo/{util → functional}/logging.rb +1 -1
  29. data/lib/mongo/{util → functional}/read_preference.rb +49 -1
  30. data/lib/mongo/{util → functional}/uri_parser.rb +81 -69
  31. data/lib/mongo/{util → functional}/write_concern.rb +2 -1
  32. data/{test/unit/pool_test.rb → lib/mongo/gridfs.rb} +5 -10
  33. data/lib/mongo/gridfs/grid.rb +1 -3
  34. data/lib/mongo/gridfs/grid_ext.rb +1 -1
  35. data/lib/mongo/gridfs/grid_file_system.rb +1 -1
  36. data/lib/mongo/gridfs/grid_io.rb +1 -1
  37. data/lib/mongo/legacy.rb +63 -8
  38. data/lib/mongo/mongo_client.rb +128 -154
  39. data/lib/mongo/mongo_replica_set_client.rb +17 -11
  40. data/lib/mongo/mongo_sharded_client.rb +2 -1
  41. data/lib/mongo/networking.rb +19 -10
  42. data/lib/mongo/utils.rb +19 -0
  43. data/lib/mongo/{util → utils}/conversions.rb +1 -1
  44. data/lib/mongo/{util → utils}/core_ext.rb +1 -1
  45. data/lib/mongo/{util → utils}/server_version.rb +1 -1
  46. data/lib/mongo/{util → utils}/support.rb +10 -57
  47. data/lib/mongo/{util → utils}/thread_local_variable_manager.rb +1 -1
  48. data/test/functional/authentication_test.rb +8 -21
  49. data/test/functional/bulk_write_collection_view_test.rb +782 -0
  50. data/test/functional/{connection_test.rb → client_test.rb} +153 -78
  51. data/test/functional/collection_test.rb +343 -97
  52. data/test/functional/collection_writer_test.rb +83 -0
  53. data/test/functional/conversions_test.rb +1 -3
  54. data/test/functional/cursor_fail_test.rb +3 -3
  55. data/test/functional/cursor_message_test.rb +3 -3
  56. data/test/functional/cursor_test.rb +38 -3
  57. data/test/functional/db_api_test.rb +5 -5
  58. data/test/functional/db_connection_test.rb +2 -2
  59. data/test/functional/db_test.rb +35 -11
  60. data/test/functional/grid_file_system_test.rb +2 -2
  61. data/test/functional/grid_io_test.rb +2 -2
  62. data/test/functional/grid_test.rb +2 -2
  63. data/test/functional/pool_test.rb +2 -3
  64. data/test/functional/safe_test.rb +5 -5
  65. data/test/functional/ssl_test.rb +22 -102
  66. data/test/functional/support_test.rb +1 -1
  67. data/test/functional/timeout_test.rb +6 -22
  68. data/test/functional/uri_test.rb +113 -12
  69. data/test/functional/write_concern_test.rb +6 -6
  70. data/test/helpers/general.rb +50 -0
  71. data/test/helpers/test_unit.rb +309 -0
  72. data/test/replica_set/authentication_test.rb +8 -23
  73. data/test/replica_set/basic_test.rb +41 -14
  74. data/test/replica_set/client_test.rb +179 -117
  75. data/test/replica_set/complex_connect_test.rb +6 -7
  76. data/test/replica_set/connection_test.rb +46 -38
  77. data/test/replica_set/count_test.rb +2 -2
  78. data/test/replica_set/cursor_test.rb +8 -8
  79. data/test/replica_set/insert_test.rb +64 -2
  80. data/test/replica_set/max_values_test.rb +59 -10
  81. data/test/replica_set/pinning_test.rb +2 -2
  82. data/test/replica_set/query_test.rb +2 -2
  83. data/test/replica_set/read_preference_test.rb +6 -6
  84. data/test/replica_set/refresh_test.rb +7 -7
  85. data/test/replica_set/replication_ack_test.rb +5 -5
  86. data/test/replica_set/ssl_test.rb +24 -106
  87. data/test/sharded_cluster/basic_test.rb +43 -15
  88. data/test/shared/authentication/basic_auth_shared.rb +215 -0
  89. data/test/shared/authentication/sasl_plain_shared.rb +96 -0
  90. data/test/shared/ssl_shared.rb +173 -0
  91. data/test/test_helper.rb +31 -199
  92. data/test/threading/basic_test.rb +29 -3
  93. data/test/tools/mongo_config.rb +45 -20
  94. data/test/tools/mongo_config_test.rb +1 -1
  95. data/test/unit/client_test.rb +136 -57
  96. data/test/unit/collection_test.rb +31 -55
  97. data/test/unit/connection_test.rb +135 -72
  98. data/test/unit/cursor_test.rb +2 -2
  99. data/test/unit/db_test.rb +19 -15
  100. data/test/unit/grid_test.rb +2 -2
  101. data/test/unit/mongo_sharded_client_test.rb +17 -15
  102. data/test/unit/node_test.rb +2 -2
  103. data/test/unit/pool_manager_test.rb +7 -5
  104. data/test/unit/read_pref_test.rb +82 -2
  105. data/test/unit/read_test.rb +14 -14
  106. data/test/unit/safe_test.rb +9 -9
  107. data/test/unit/sharding_pool_manager_test.rb +11 -5
  108. data/test/unit/write_concern_test.rb +9 -9
  109. metadata +71 -56
  110. metadata.gz.sig +0 -0
  111. data/test/functional/threading_test.rb +0 -109
  112. data/test/shared/authentication.rb +0 -121
  113. data/test/unit/util_test.rb +0 -69
@@ -1,4 +1,4 @@
1
- # Copyright (C) 2013 10gen Inc.
1
+ # Copyright (C) 2009-2013 MongoDB, Inc.
2
2
  #
3
3
  # Licensed under the Apache License, Version 2.0 (the "License");
4
4
  # you may not use this file except in compliance with the License.
@@ -26,7 +26,9 @@ module Mongo
26
26
  :seeds,
27
27
  :pools,
28
28
  :max_bson_size,
29
- :max_message_size
29
+ :max_message_size,
30
+ :max_wire_version,
31
+ :min_wire_version
30
32
 
31
33
  # Create a new set of connection pools.
32
34
  #
@@ -49,6 +51,8 @@ module Mongo
49
51
  @refresh_required = false
50
52
  @max_bson_size = DEFAULT_MAX_BSON_SIZE
51
53
  @max_message_size = @max_bson_size * MESSAGE_SIZE_FACTOR
54
+ @max_wire_version = 0
55
+ @min_wire_version = 0
52
56
  @connect_mutex = Mutex.new
53
57
  thread_local[:locks][:connecting_manager] = false
54
58
  end
@@ -147,6 +151,8 @@ module Mongo
147
151
  unless @members.size == 0
148
152
  @max_bson_size = @members.map(&:max_bson_size).min
149
153
  @max_message_size = @members.map(&:max_message_size).min
154
+ @max_wire_version = @members.map(&:max_wire_version).min
155
+ @min_wire_version = @members.map(&:min_wire_version).max
150
156
  end
151
157
  end
152
158
 
@@ -1,4 +1,4 @@
1
- # Copyright (C) 2013 10gen Inc.
1
+ # Copyright (C) 2009-2013 MongoDB, Inc.
2
2
  #
3
3
  # Licensed under the Apache License, Version 2.0 (the "License");
4
4
  # you may not use this file except in compliance with the License.
@@ -0,0 +1,18 @@
1
+ # Copyright (C) 2009-2013 MongoDB, Inc.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ require 'mongo/connection/socket/socket_util.rb'
16
+ require 'mongo/connection/socket/ssl_socket.rb'
17
+ require 'mongo/connection/socket/tcp_socket.rb'
18
+ require 'mongo/connection/socket/unix_socket.rb'
@@ -1,4 +1,4 @@
1
- # Copyright (C) 2013 10gen Inc.
1
+ # Copyright (C) 2009-2013 MongoDB, Inc.
2
2
  #
3
3
  # Licensed under the Apache License, Version 2.0 (the "License");
4
4
  # you may not use this file except in compliance with the License.
@@ -12,9 +12,12 @@
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
14
 
15
+ require 'socket'
16
+ require 'timeout'
17
+
15
18
  module SocketUtil
16
19
 
17
- attr_accessor :pool, :pid
20
+ attr_accessor :pool, :pid, :auths
18
21
 
19
22
  def checkout
20
23
  @pool.checkout if @pool
@@ -1,4 +1,4 @@
1
- # Copyright (C) 2013 10gen Inc.
1
+ # Copyright (C) 2009-2013 MongoDB, Inc.
2
2
  #
3
3
  # Licensed under the Apache License, Version 2.0 (the "License");
4
4
  # you may not use this file except in compliance with the License.
@@ -12,9 +12,7 @@
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
14
 
15
- require 'socket'
16
15
  require 'openssl'
17
- require 'timeout'
18
16
 
19
17
  module Mongo
20
18
 
@@ -25,9 +23,10 @@ module Mongo
25
23
  include SocketUtil
26
24
 
27
25
  def initialize(host, port, op_timeout=nil, connect_timeout=nil, opts={})
28
- @pid = Process.pid
29
26
  @op_timeout = op_timeout
30
27
  @connect_timeout = connect_timeout
28
+ @pid = Process.pid
29
+ @auths = Set.new
31
30
 
32
31
  @tcp_socket = ::TCPSocket.new(host, port)
33
32
  @tcp_socket.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1)
@@ -1,4 +1,4 @@
1
- # Copyright (C) 2013 10gen Inc.
1
+ # Copyright (C) 2009-2013 MongoDB, Inc.
2
2
  #
3
3
  # Licensed under the Apache License, Version 2.0 (the "License");
4
4
  # you may not use this file except in compliance with the License.
@@ -12,9 +12,6 @@
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
14
 
15
- require 'socket'
16
- require 'timeout'
17
-
18
15
  module Mongo
19
16
  # Wrapper class for Socket
20
17
  #
@@ -28,25 +25,38 @@ module Mongo
28
25
  @op_timeout = op_timeout
29
26
  @connect_timeout = connect_timeout
30
27
  @pid = Process.pid
28
+ @auths = Set.new
31
29
 
32
- # TODO: Prefer ipv6 if server is ipv6 enabled
33
- @address = Socket.getaddrinfo(host, nil, Socket::AF_INET).first[3]
34
- @port = port
35
-
36
- @socket_address = Socket.pack_sockaddr_in(@port, @address)
37
- @socket = Socket.new(Socket::AF_INET, Socket::SOCK_STREAM, 0)
38
- @socket.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1)
30
+ @socket = handle_connect(host, port)
31
+ end
39
32
 
40
- connect
33
+ def handle_connect(host, port)
34
+ error = nil
35
+ # Following python's lead (see PYTHON-356)
36
+ family = host == 'localhost' ? Socket::AF_INET : Socket::AF_UNSPEC
37
+ addr_info = Socket.getaddrinfo(host, nil, family, Socket::SOCK_STREAM)
38
+ addr_info.each do |info|
39
+ begin
40
+ sock = Socket.new(info[4], Socket::SOCK_STREAM, 0)
41
+ sock.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1)
42
+ socket_address = Socket.pack_sockaddr_in(port, info[3])
43
+ connect(sock, socket_address)
44
+ return sock
45
+ rescue IOError, SystemCallError => e
46
+ error = e
47
+ sock.close if sock
48
+ end
49
+ end
50
+ raise error
41
51
  end
42
52
 
43
- def connect
53
+ def connect(socket, socket_address)
44
54
  if @connect_timeout
45
55
  Timeout::timeout(@connect_timeout, ConnectionTimeoutError) do
46
- @socket.connect(@socket_address)
56
+ socket.connect(socket_address)
47
57
  end
48
58
  else
49
- @socket.connect(@socket_address)
59
+ socket.connect(socket_address)
50
60
  end
51
61
  end
52
62
 
@@ -1,4 +1,4 @@
1
- # Copyright (C) 2013 10gen Inc.
1
+ # Copyright (C) 2009-2013 MongoDB, Inc.
2
2
  #
3
3
  # Licensed under the Apache License, Version 2.0 (the "License");
4
4
  # you may not use this file except in compliance with the License.
@@ -12,9 +12,10 @@
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
14
 
15
- require 'socket'
16
-
17
15
  module Mongo
16
+
17
+ attr_accessor :auths
18
+
18
19
  # Wrapper class for Socket
19
20
  #
20
21
  # Emulates UNIXSocket with operation and connection timeout
@@ -24,6 +25,8 @@ module Mongo
24
25
  def initialize(socket_path, port=:socket, op_timeout=nil, connect_timeout=nil, opts={})
25
26
  @op_timeout = op_timeout
26
27
  @connect_timeout = connect_timeout
28
+ @pid = Process.pid
29
+ @auths = Set.new
27
30
 
28
31
  @address = socket_path
29
32
  @port = :socket # purposely override input
@@ -34,4 +37,3 @@ module Mongo
34
37
  end
35
38
  end
36
39
  end
37
-
@@ -1,4 +1,4 @@
1
- # Copyright (C) 2013 10gen Inc.
1
+ # Copyright (C) 2009-2013 MongoDB, Inc.
2
2
  #
3
3
  # Licensed under the Apache License, Version 2.0 (the "License");
4
4
  # you may not use this file except in compliance with the License.
@@ -26,7 +26,8 @@ module Mongo
26
26
  :order, :hint, :snapshot, :timeout,
27
27
  :full_collection_name, :transformer,
28
28
  :options, :cursor_id, :show_disk_loc,
29
- :comment, :read, :tag_sets, :acceptable_latency
29
+ :comment, :compile_regex, :read, :tag_sets,
30
+ :acceptable_latency
30
31
 
31
32
  # Create a new cursor.
32
33
  #
@@ -34,54 +35,57 @@ module Mongo
34
35
  # similar methods. Application developers shouldn't have to create cursors manually.
35
36
  #
36
37
  # @return [Cursor]
37
- #
38
- # @core cursors constructor_details
39
38
  def initialize(collection, opts={})
40
- @cursor_id = nil
39
+ opts = opts.dup
40
+ @cursor_id = opts.delete(:cursor_id)
41
41
  @db = collection.db
42
42
  @collection = collection
43
43
  @connection = @db.connection
44
44
  @logger = @connection.logger
45
45
 
46
46
  # Query selector
47
- @selector = opts[:selector] || {}
47
+ @selector = opts.delete(:selector) || {}
48
+
49
+ # Query pre-serialized bson to append
50
+ @bson = @selector.delete(:bson)
48
51
 
49
52
  # Special operators that form part of $query
50
- @order = opts[:order]
51
- @explain = opts[:explain]
52
- @hint = opts[:hint]
53
- @snapshot = opts[:snapshot]
54
- @max_scan = opts.fetch(:max_scan, nil)
55
- @return_key = opts.fetch(:return_key, nil)
56
- @show_disk_loc = opts.fetch(:show_disk_loc, nil)
57
- @comment = opts[:comment]
53
+ @order = opts.delete(:order)
54
+ @explain = opts.delete(:explain)
55
+ @hint = opts.delete(:hint)
56
+ @snapshot = opts.delete(:snapshot)
57
+ @max_scan = opts.delete(:max_scan)
58
+ @return_key = opts.delete(:return_key)
59
+ @show_disk_loc = opts.delete(:show_disk_loc)
60
+ @comment = opts.delete(:comment)
61
+ @compile_regex = opts.key?(:compile_regex) ? opts.delete(:compile_regex) : true
58
62
 
59
63
  # Wire-protocol settings
60
- @fields = convert_fields_for_query(opts[:fields])
61
- @skip = opts[:skip] || 0
62
- @limit = opts[:limit] || 0
63
- @tailable = opts[:tailable] || false
64
- @timeout = opts.fetch(:timeout, true)
65
- @options = 0
64
+ @fields = convert_fields_for_query(opts.delete(:fields))
65
+ @skip = opts.delete(:skip) || 0
66
+ @limit = opts.delete(:limit) || 0
67
+ @tailable = opts.delete(:tailable)
68
+ @timeout = opts.key?(:timeout) ? opts.delete(:timeout) : true
69
+ @options = 0
66
70
 
67
71
  # Use this socket for the query
68
- @socket = opts[:socket]
69
- @pool = nil
72
+ @socket = opts.delete(:socket)
73
+ @pool = opts.delete(:pool)
70
74
 
71
- @closed = false
72
- @query_run = false
75
+ @closed = false
76
+ @query_run = false
73
77
 
74
- @transformer = opts[:transformer]
75
- @read = opts[:read] || @collection.read
78
+ @transformer = opts.delete(:transformer)
79
+ @read = opts.delete(:read) || @collection.read
76
80
  Mongo::ReadPreference::validate(@read)
77
- @tag_sets = opts[:tag_sets] || @collection.tag_sets
78
- @acceptable_latency = opts[:acceptable_latency] || @collection.acceptable_latency
81
+ @tag_sets = opts.delete(:tag_sets) || @collection.tag_sets
82
+ @acceptable_latency = opts.delete(:acceptable_latency) || @collection.acceptable_latency
79
83
 
80
- batch_size(opts[:batch_size] || 0)
84
+ batch_size(opts.delete(:batch_size) || 0)
81
85
 
82
86
  @full_collection_name = "#{@collection.db.name}.#{@collection.name}"
83
- @cache = []
84
- @returned = 0
87
+ @cache = opts.delete(:first_batch) || []
88
+ @returned = 0
85
89
 
86
90
  if(!@timeout)
87
91
  add_option(OP_QUERY_NO_CURSOR_TIMEOUT)
@@ -93,11 +97,19 @@ module Mongo
93
97
  add_option(OP_QUERY_TAILABLE)
94
98
  end
95
99
 
100
+ # If a cursor_id is provided, this is a cursor for a command
101
+ if @cursor_id
102
+ @command_cursor = true
103
+ @query_run = true
104
+ end
105
+
96
106
  if @collection.name =~ /^\$cmd/ || @collection.name =~ /^system/
97
107
  @command = true
98
108
  else
99
109
  @command = false
100
110
  end
111
+
112
+ @opts = opts
101
113
  end
102
114
 
103
115
  # Guess whether the cursor is alive on the server.
@@ -126,18 +138,25 @@ module Mongo
126
138
  end
127
139
  doc = @cache.shift
128
140
 
129
- if doc && doc['$err']
130
- err = doc['$err']
141
+ if doc && (err = doc['errmsg'] || doc['$err']) # assignment
142
+ code = doc['code']
131
143
 
132
144
  # If the server has stopped being the master (e.g., it's one of a
133
145
  # pair but it has died or something like that) then we close that
134
146
  # connection. The next request will re-open on master server.
135
147
  if err.include?("not master")
136
148
  @connection.close
137
- raise ConnectionFailure.new(err, doc['code'], doc)
149
+ raise ConnectionFailure.new(err, code, doc)
138
150
  end
139
151
 
140
- raise OperationFailure.new(err, doc['code'], doc)
152
+ # Handle server side operation execution timeout
153
+ if code == 50
154
+ raise ExecutionTimeout.new(err, code, doc)
155
+ end
156
+
157
+ raise OperationFailure.new(err, code, doc)
158
+ elsif doc && (writeConcernError = doc['writeConcernError']) && writeConcernError['errInfo'] == {"wtimeout" => true} # assignment
159
+ raise OperationFailure.new('timeout ' + writeConcernError['errmsg'], writeConcernError['code'], doc)
141
160
  end
142
161
 
143
162
  if @transformer.nil?
@@ -151,6 +170,7 @@ module Mongo
151
170
  # Reset this cursor on the server. Cursor options, such as the
152
171
  # query string and the values for skip and limit, are preserved.
153
172
  def rewind!
173
+ check_command_cursor
154
174
  close
155
175
  @cache.clear
156
176
  @cursor_id = nil
@@ -175,6 +195,7 @@ module Mongo
175
195
  #
176
196
  # @raise [OperationFailure] on a database error.
177
197
  def count(skip_and_limit = false)
198
+ check_command_cursor
178
199
  command = BSON::OrderedHash["count", @collection.name, "query", @selector]
179
200
 
180
201
  if skip_and_limit
@@ -219,8 +240,6 @@ module Mongo
219
240
  # @return [Integer] the current number_to_return if no parameter is given.
220
241
  #
221
242
  # @raise [InvalidOperation] if this cursor has already been used.
222
- #
223
- # @core limit limit-instance_method
224
243
  def limit(number_to_return=nil)
225
244
  return @limit unless number_to_return
226
245
  check_modifiable
@@ -250,6 +269,31 @@ module Mongo
250
269
  self
251
270
  end
252
271
 
272
+ # Instruct the server to abort queries after they exceed the specified
273
+ # wall-clock execution time.
274
+ #
275
+ # A query that completes in under its time limit will "roll over"
276
+ # remaining time to the first getmore op (which will then "roll over"
277
+ # its remaining time to the second getmore op and so on, until the
278
+ # time limit is hit).
279
+ #
280
+ # Cursors returned by successful time-limited queries will still obey
281
+ # the default cursor idle timeout (unless the "no cursor idle timeout"
282
+ # flag has been set).
283
+ #
284
+ # @note This will only have an effect in MongoDB 2.5+
285
+ #
286
+ # @param max_time_ms [Fixnum] max execution time (in milliseconds)
287
+ #
288
+ # @return [Fixnum, Cursor] either the current max_time_ms or cursor
289
+ def max_time_ms(max_time_ms=nil)
290
+ return @max_time_ms unless max_time_ms
291
+ check_modifiable
292
+
293
+ @max_time_ms = max_time_ms
294
+ self
295
+ end
296
+
253
297
  # Set the batch size for server responses.
254
298
  #
255
299
  # Note that the batch size will take effect only on queries
@@ -317,9 +361,8 @@ module Mongo
317
361
  # Get the explain plan for this cursor.
318
362
  #
319
363
  # @return [Hash] a document containing the explain plan for this cursor.
320
- #
321
- # @core explain explain-instance_method
322
364
  def explain
365
+ check_command_cursor
323
366
  c = Cursor.new(@collection,
324
367
  query_options_hash.merge(:limit => -@limit.abs, :explain => true))
325
368
  explanation = c.next_document
@@ -496,13 +539,13 @@ module Mongo
496
539
  socket = @socket || checkout_socket_from_connection
497
540
  results, @n_received, @cursor_id = @connection.receive_message(
498
541
  Mongo::Constants::OP_QUERY, message, nil, socket, @command,
499
- nil, exhaust?)
542
+ nil, exhaust?, compile_regex?)
500
543
  rescue ConnectionFailure => ex
501
544
  socket.close if socket
502
545
  @pool = nil
503
546
  @connection.unpin_pool
504
547
  @connection.refresh
505
- if tries < 3 && !@socket && (!@command || Mongo::Support::secondary_ok?(@selector))
548
+ if tries < 3 && !@socket && (!@command || Mongo::ReadPreference::secondary_ok?(@selector))
506
549
  tries += 1
507
550
  retry
508
551
  else
@@ -548,7 +591,8 @@ module Mongo
548
591
 
549
592
  begin
550
593
  results, @n_received, @cursor_id = @connection.receive_message(
551
- Mongo::Constants::OP_GET_MORE, message, nil, socket, @command, nil)
594
+ Mongo::Constants::OP_GET_MORE, message, nil, socket, @command,
595
+ nil, exhaust?, compile_regex?)
552
596
  ensure
553
597
  socket.checkin
554
598
  end
@@ -562,7 +606,7 @@ module Mongo
562
606
  begin
563
607
  if @pool
564
608
  socket = @pool.checkout
565
- elsif @command && !Mongo::Support::secondary_ok?(@selector)
609
+ elsif @command && !Mongo::ReadPreference::secondary_ok?(@selector)
566
610
  socket = @connection.checkout_reader({:mode => :primary})
567
611
  else
568
612
  socket = @connection.checkout_reader(read_preference)
@@ -580,13 +624,24 @@ module Mongo
580
624
  end
581
625
 
582
626
  def construct_query_message
583
- message = BSON::ByteBuffer.new("", @connection.max_message_size)
627
+ message = BSON::ByteBuffer.new("", @connection.max_bson_size + MongoClient::COMMAND_HEADROOM)
584
628
  message.put_int(@options)
585
629
  BSON::BSON_RUBY.serialize_cstr(message, "#{@db.name}.#{@collection.name}")
586
630
  message.put_int(@skip)
587
631
  @batch_size > 1 ? message.put_int(@batch_size) : message.put_int(@limit)
588
- spec = query_contains_special_fields? ? construct_query_spec : @selector
589
- message.put_binary(BSON::BSON_CODER.serialize(spec, false, false, @connection.max_bson_size).to_s)
632
+ if query_contains_special_fields? && @bson # costs two serialize calls
633
+ query_message = BSON::BSON_CODER.serialize(@selector, false, false, @connection.max_bson_size + MongoClient::APPEND_HEADROOM)
634
+ query_message.grow(@bson)
635
+ query_spec = construct_query_spec
636
+ query_spec.delete('$query')
637
+ query_message.grow(BSON::BSON_CODER.serialize(query_spec, false, false, @connection.max_bson_size))
638
+ else # costs only one serialize call
639
+ spec = query_contains_special_fields? ? construct_query_spec : @selector
640
+ spec.merge!(@opts)
641
+ query_message = BSON::BSON_CODER.serialize(spec, false, false, @connection.max_bson_size + MongoClient::APPEND_HEADROOM)
642
+ query_message.grow(@bson) if @bson
643
+ end
644
+ message.put_binary(query_message.to_s)
590
645
  message.put_binary(BSON::BSON_CODER.serialize(@fields, false, false, @connection.max_bson_size).to_s) if @fields
591
646
  message
592
647
  end
@@ -612,6 +667,7 @@ module Mongo
612
667
  spec['$returnKey'] = true if @return_key
613
668
  spec['$showDiskLoc'] = true if @show_disk_loc
614
669
  spec['$comment'] = @comment if @comment
670
+ spec['$maxTimeMS'] = @max_time_ms if @max_time_ms
615
671
  if needs_read_pref?
616
672
  read_pref = Mongo::ReadPreference::mongos(@read, @tag_sets)
617
673
  spec['$readPreference'] = read_pref if read_pref
@@ -625,7 +681,7 @@ module Mongo
625
681
 
626
682
  def query_contains_special_fields?
627
683
  @order || @explain || @hint || @snapshot || @show_disk_loc ||
628
- @max_scan || @return_key || @comment || needs_read_pref?
684
+ @max_scan || @return_key || @comment || @max_time_ms || needs_read_pref?
629
685
  end
630
686
 
631
687
  def close_cursor_if_query_complete
@@ -646,5 +702,15 @@ module Mongo
646
702
  raise InvalidOperation, "Cannot modify the query once it has been run or closed."
647
703
  end
648
704
  end
705
+
706
+ def check_command_cursor
707
+ if @command_cursor
708
+ raise InvalidOperation, "Cannot call #{caller.first} on command cursors"
709
+ end
710
+ end
711
+
712
+ def compile_regex?
713
+ @compile_regex
714
+ end
649
715
  end
650
716
  end