mongo 1.3.0 → 1.12.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (185) hide show
  1. checksums.yaml +7 -0
  2. checksums.yaml.gz.sig +0 -0
  3. data/{LICENSE.txt → LICENSE} +1 -1
  4. data/README.md +122 -271
  5. data/Rakefile +25 -209
  6. data/VERSION +1 -0
  7. data/bin/mongo_console +31 -9
  8. data/lib/mongo/bulk_write_collection_view.rb +387 -0
  9. data/lib/mongo/collection.rb +576 -269
  10. data/lib/mongo/collection_writer.rb +364 -0
  11. data/lib/mongo/connection/node.rb +249 -0
  12. data/lib/mongo/connection/pool.rb +340 -0
  13. data/lib/mongo/connection/pool_manager.rb +320 -0
  14. data/lib/mongo/connection/sharding_pool_manager.rb +67 -0
  15. data/lib/mongo/connection/socket/socket_util.rb +37 -0
  16. data/lib/mongo/connection/socket/ssl_socket.rb +95 -0
  17. data/lib/mongo/connection/socket/tcp_socket.rb +87 -0
  18. data/lib/mongo/connection/socket/unix_socket.rb +39 -0
  19. data/lib/mongo/connection/socket.rb +18 -0
  20. data/lib/mongo/connection.rb +7 -875
  21. data/lib/mongo/cursor.rb +403 -117
  22. data/lib/mongo/db.rb +444 -243
  23. data/lib/mongo/exception.rb +145 -0
  24. data/lib/mongo/functional/authentication.rb +455 -0
  25. data/lib/mongo/functional/logging.rb +85 -0
  26. data/lib/mongo/functional/read_preference.rb +183 -0
  27. data/lib/mongo/functional/scram.rb +556 -0
  28. data/lib/mongo/functional/uri_parser.rb +409 -0
  29. data/lib/mongo/functional/write_concern.rb +66 -0
  30. data/lib/mongo/functional.rb +20 -0
  31. data/lib/mongo/gridfs/grid.rb +30 -24
  32. data/lib/mongo/gridfs/grid_ext.rb +6 -10
  33. data/lib/mongo/gridfs/grid_file_system.rb +38 -20
  34. data/lib/mongo/gridfs/grid_io.rb +84 -75
  35. data/lib/mongo/gridfs.rb +18 -0
  36. data/lib/mongo/legacy.rb +140 -0
  37. data/lib/mongo/mongo_client.rb +697 -0
  38. data/lib/mongo/mongo_replica_set_client.rb +535 -0
  39. data/lib/mongo/mongo_sharded_client.rb +159 -0
  40. data/lib/mongo/networking.rb +372 -0
  41. data/lib/mongo/{util → utils}/conversions.rb +29 -8
  42. data/lib/mongo/{util → utils}/core_ext.rb +28 -18
  43. data/lib/mongo/{util → utils}/server_version.rb +4 -6
  44. data/lib/mongo/{util → utils}/support.rb +29 -31
  45. data/lib/mongo/utils/thread_local_variable_manager.rb +25 -0
  46. data/lib/mongo/utils.rb +19 -0
  47. data/lib/mongo.rb +51 -50
  48. data/mongo.gemspec +29 -32
  49. data/test/functional/authentication_test.rb +39 -0
  50. data/test/functional/bulk_api_stress_test.rb +133 -0
  51. data/test/functional/bulk_write_collection_view_test.rb +1198 -0
  52. data/test/functional/client_test.rb +627 -0
  53. data/test/functional/collection_test.rb +2175 -0
  54. data/test/functional/collection_writer_test.rb +83 -0
  55. data/test/{conversions_test.rb → functional/conversions_test.rb} +47 -3
  56. data/test/functional/cursor_fail_test.rb +57 -0
  57. data/test/functional/cursor_message_test.rb +56 -0
  58. data/test/functional/cursor_test.rb +683 -0
  59. data/test/functional/db_api_test.rb +835 -0
  60. data/test/functional/db_connection_test.rb +25 -0
  61. data/test/functional/db_test.rb +348 -0
  62. data/test/functional/grid_file_system_test.rb +285 -0
  63. data/test/{grid_io_test.rb → functional/grid_io_test.rb} +72 -11
  64. data/test/{grid_test.rb → functional/grid_test.rb} +88 -15
  65. data/test/functional/pool_test.rb +136 -0
  66. data/test/functional/safe_test.rb +98 -0
  67. data/test/functional/ssl_test.rb +29 -0
  68. data/test/functional/support_test.rb +62 -0
  69. data/test/functional/timeout_test.rb +60 -0
  70. data/test/functional/uri_test.rb +446 -0
  71. data/test/functional/write_concern_test.rb +118 -0
  72. data/test/helpers/general.rb +50 -0
  73. data/test/helpers/test_unit.rb +476 -0
  74. data/test/replica_set/authentication_test.rb +37 -0
  75. data/test/replica_set/basic_test.rb +189 -0
  76. data/test/replica_set/client_test.rb +393 -0
  77. data/test/replica_set/connection_test.rb +138 -0
  78. data/test/replica_set/count_test.rb +66 -0
  79. data/test/replica_set/cursor_test.rb +220 -0
  80. data/test/replica_set/insert_test.rb +157 -0
  81. data/test/replica_set/max_values_test.rb +151 -0
  82. data/test/replica_set/pinning_test.rb +105 -0
  83. data/test/replica_set/query_test.rb +73 -0
  84. data/test/replica_set/read_preference_test.rb +219 -0
  85. data/test/replica_set/refresh_test.rb +211 -0
  86. data/test/replica_set/replication_ack_test.rb +95 -0
  87. data/test/replica_set/ssl_test.rb +32 -0
  88. data/test/sharded_cluster/basic_test.rb +203 -0
  89. data/test/shared/authentication/basic_auth_shared.rb +260 -0
  90. data/test/shared/authentication/bulk_api_auth_shared.rb +249 -0
  91. data/test/shared/authentication/gssapi_shared.rb +176 -0
  92. data/test/shared/authentication/sasl_plain_shared.rb +96 -0
  93. data/test/shared/authentication/scram_shared.rb +92 -0
  94. data/test/shared/ssl_shared.rb +235 -0
  95. data/test/test_helper.rb +53 -94
  96. data/test/threading/basic_test.rb +120 -0
  97. data/test/tools/mongo_config.rb +708 -0
  98. data/test/tools/mongo_config_test.rb +160 -0
  99. data/test/unit/client_test.rb +381 -0
  100. data/test/unit/collection_test.rb +89 -53
  101. data/test/unit/connection_test.rb +282 -32
  102. data/test/unit/cursor_test.rb +206 -8
  103. data/test/unit/db_test.rb +55 -13
  104. data/test/unit/grid_test.rb +43 -16
  105. data/test/unit/mongo_sharded_client_test.rb +48 -0
  106. data/test/unit/node_test.rb +93 -0
  107. data/test/unit/pool_manager_test.rb +111 -0
  108. data/test/unit/read_pref_test.rb +406 -0
  109. data/test/unit/read_test.rb +159 -0
  110. data/test/unit/safe_test.rb +69 -36
  111. data/test/unit/sharding_pool_manager_test.rb +84 -0
  112. data/test/unit/write_concern_test.rb +175 -0
  113. data.tar.gz.sig +3 -0
  114. metadata +227 -216
  115. metadata.gz.sig +0 -0
  116. data/docs/CREDITS.md +0 -123
  117. data/docs/FAQ.md +0 -116
  118. data/docs/GridFS.md +0 -158
  119. data/docs/HISTORY.md +0 -244
  120. data/docs/RELEASES.md +0 -33
  121. data/docs/REPLICA_SETS.md +0 -72
  122. data/docs/TUTORIAL.md +0 -247
  123. data/docs/WRITE_CONCERN.md +0 -28
  124. data/lib/mongo/exceptions.rb +0 -71
  125. data/lib/mongo/gridfs/grid_io_fix.rb +0 -38
  126. data/lib/mongo/repl_set_connection.rb +0 -342
  127. data/lib/mongo/test.rb +0 -20
  128. data/lib/mongo/util/pool.rb +0 -177
  129. data/lib/mongo/util/uri_parser.rb +0 -185
  130. data/test/async/collection_test.rb +0 -224
  131. data/test/async/connection_test.rb +0 -24
  132. data/test/async/cursor_test.rb +0 -162
  133. data/test/async/worker_pool_test.rb +0 -99
  134. data/test/auxillary/1.4_features.rb +0 -166
  135. data/test/auxillary/authentication_test.rb +0 -68
  136. data/test/auxillary/autoreconnect_test.rb +0 -41
  137. data/test/auxillary/fork_test.rb +0 -30
  138. data/test/auxillary/repl_set_auth_test.rb +0 -58
  139. data/test/auxillary/slave_connection_test.rb +0 -36
  140. data/test/auxillary/threaded_authentication_test.rb +0 -101
  141. data/test/bson/binary_test.rb +0 -15
  142. data/test/bson/bson_test.rb +0 -649
  143. data/test/bson/byte_buffer_test.rb +0 -208
  144. data/test/bson/hash_with_indifferent_access_test.rb +0 -38
  145. data/test/bson/json_test.rb +0 -17
  146. data/test/bson/object_id_test.rb +0 -154
  147. data/test/bson/ordered_hash_test.rb +0 -204
  148. data/test/bson/timestamp_test.rb +0 -24
  149. data/test/collection_test.rb +0 -910
  150. data/test/connection_test.rb +0 -309
  151. data/test/cursor_fail_test.rb +0 -75
  152. data/test/cursor_message_test.rb +0 -43
  153. data/test/cursor_test.rb +0 -483
  154. data/test/db_api_test.rb +0 -726
  155. data/test/db_connection_test.rb +0 -15
  156. data/test/db_test.rb +0 -287
  157. data/test/grid_file_system_test.rb +0 -243
  158. data/test/load/resque/load.rb +0 -21
  159. data/test/load/resque/processor.rb +0 -26
  160. data/test/load/thin/load.rb +0 -24
  161. data/test/load/unicorn/load.rb +0 -23
  162. data/test/load/unicorn/unicorn.rb +0 -29
  163. data/test/replica_sets/connect_test.rb +0 -94
  164. data/test/replica_sets/connection_string_test.rb +0 -32
  165. data/test/replica_sets/count_test.rb +0 -35
  166. data/test/replica_sets/insert_test.rb +0 -53
  167. data/test/replica_sets/pooled_insert_test.rb +0 -55
  168. data/test/replica_sets/query_secondaries.rb +0 -96
  169. data/test/replica_sets/query_test.rb +0 -51
  170. data/test/replica_sets/replication_ack_test.rb +0 -66
  171. data/test/replica_sets/rs_test_helper.rb +0 -27
  172. data/test/safe_test.rb +0 -68
  173. data/test/support/hash_with_indifferent_access.rb +0 -186
  174. data/test/support/keys.rb +0 -45
  175. data/test/support_test.rb +0 -18
  176. data/test/threading/threading_with_large_pool_test.rb +0 -90
  177. data/test/threading_test.rb +0 -87
  178. data/test/tools/auth_repl_set_manager.rb +0 -14
  179. data/test/tools/load.rb +0 -58
  180. data/test/tools/repl_set_manager.rb +0 -266
  181. data/test/tools/sharding_manager.rb +0 -202
  182. data/test/tools/test.rb +0 -4
  183. data/test/unit/pool_test.rb +0 -9
  184. data/test/unit/repl_set_connection_test.rb +0 -59
  185. data/test/uri_test.rb +0 -91
@@ -1,342 +0,0 @@
1
- # encoding: UTF-8
2
-
3
- # --
4
- # Copyright (C) 2008-2011 10gen Inc.
5
- #
6
- # Licensed under the Apache License, Version 2.0 (the "License");
7
- # you may not use this file except in compliance with the License.
8
- # You may obtain a copy of the License at
9
- #
10
- # http://www.apache.org/licenses/LICENSE-2.0
11
- #
12
- # Unless required by applicable law or agreed to in writing, software
13
- # distributed under the License is distributed on an "AS IS" BASIS,
14
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
- # See the License for the specific language governing permissions and
16
- # limitations under the License.
17
- # ++
18
-
19
- module Mongo
20
-
21
- # Instantiates and manages connections to a MongoDB replica set.
22
- class ReplSetConnection < Connection
23
- attr_reader :nodes, :secondaries, :arbiters, :read_pool, :secondary_pools
24
-
25
- # Create a connection to a MongoDB replica set.
26
- #
27
- # Once connected to a replica set, you can find out which nodes are primary, secondary, and
28
- # arbiters with the corresponding accessors: Connection#primary, Connection#secondaries, and
29
- # Connection#arbiters. This is useful if your application needs to connect manually to nodes other
30
- # than the primary.
31
- #
32
- # @param [Array] args A list of host-port pairs to be used as seed nodes followed by a
33
- # hash containing any options. See the examples below for exactly how to use the constructor.
34
- #
35
- # @option options [String] :rs_name (nil) The name of the replica set to connect to. You
36
- # can use this option to verify that you're connecting to the right replica set.
37
- # @option options [Boolean, Hash] :safe (false) Set the default safe-mode options
38
- # propogated to DB objects instantiated off of this Connection. This
39
- # default can be overridden upon instantiation of any DB by explicity setting a :safe value
40
- # on initialization.
41
- # @option options [Boolean] :read_secondary(false) If true, a random secondary node will be chosen,
42
- # and all reads will be directed to that node.
43
- # @option options [Logger, #debug] :logger (nil) Logger instance to receive driver operation log.
44
- # @option options [Integer] :pool_size (1) The maximum number of socket connections allowed per
45
- # connection pool. Note: this setting is relevant only for multi-threaded applications.
46
- # @option options [Float] :timeout (5.0) When all of the connections a pool are checked out,
47
- # this is the number of seconds to wait for a new connection to be released before throwing an exception.
48
- # Note: this setting is relevant only for multi-threaded applications.
49
- #
50
- # @example Connect to a replica set and provide two seed nodes. Note that the number of seed nodes does
51
- # not have to be equal to the number of replica set members. The purpose of seed nodes is to permit
52
- # the driver to find at least one replica set member even if a member is down.
53
- # ReplSetConnection.new(['localhost', 30000], ['localhost', 30001])
54
- #
55
- # @example Connect to a replica set providing two seed nodes and ensuring a connection to the replica set named 'prod':
56
- # ReplSetConnection.new(['localhost', 30000], ['localhost', 30001], :rs_name => 'prod')
57
- #
58
- # @example Connect to a replica set providing two seed nodes and allowing reads from a secondary node:
59
- # ReplSetConnection.new(['localhost', 30000], ['localhost', 30001], :read_secondary => true)
60
- #
61
- # @see http://api.mongodb.org/ruby/current/file.REPLICA_SETS.html Replica sets in Ruby
62
- #
63
- # @raise [ReplicaSetConnectionError] This is raised if a replica set name is specified and the
64
- # driver fails to connect to a replica set with that name.
65
- def initialize(*args)
66
- if args.last.is_a?(Hash)
67
- opts = args.pop
68
- else
69
- opts = {}
70
- end
71
-
72
- unless args.length > 0
73
- raise MongoArgumentError, "A ReplSetConnection requires at least one node."
74
- end
75
-
76
- # Get seed nodes
77
- @nodes = args
78
-
79
- # Replica set name
80
- @replica_set = opts[:rs_name]
81
-
82
- # Cache the various node types when connecting to a replica set.
83
- @secondaries = []
84
- @arbiters = []
85
-
86
- # Connection pools for each secondary node
87
- @secondary_pools = []
88
- @read_pool = nil
89
-
90
- # Are we allowing reads from secondaries?
91
- @read_secondary = opts.fetch(:read_secondary, false)
92
-
93
- setup(opts)
94
- end
95
-
96
- # Create a new socket and attempt to connect to master.
97
- # If successful, sets host and port to master and returns the socket.
98
- #
99
- # If connecting to a replica set, this method will replace the
100
- # initially-provided seed list with any nodes known to the set.
101
- #
102
- # @raise [ConnectionFailure] if unable to connect to any host or port.
103
- def connect
104
- close
105
- @nodes_to_try = @nodes.clone
106
-
107
- while connecting?
108
- node = @nodes_to_try.shift
109
- config = check_is_master(node)
110
-
111
- if is_primary?(config)
112
- set_primary(node)
113
- else
114
- set_auxillary(node, config)
115
- end
116
- end
117
-
118
- pick_secondary_for_read if @read_secondary
119
-
120
- if connected?
121
- BSON::BSON_CODER.update_max_bson_size(self)
122
- else
123
- if @secondary_pools.empty?
124
- close # close any existing pools and sockets
125
- raise ConnectionFailure, "Failed to connect any given host:port"
126
- else
127
- close # close any existing pools and sockets
128
- raise ConnectionFailure, "Failed to connect to primary node."
129
- end
130
- end
131
- end
132
- alias :reconnect :connect
133
-
134
- def connecting?
135
- @nodes_to_try.length > 0
136
- end
137
-
138
- # The replica set primary's host name.
139
- #
140
- # @return [String]
141
- def host
142
- super
143
- end
144
-
145
- # The replica set primary's port.
146
- #
147
- # @return [Integer]
148
- def port
149
- super
150
- end
151
-
152
- # Determine whether we're reading from a primary node. If false,
153
- # this connection connects to a secondary node and @read_secondaries is true.
154
- #
155
- # @return [Boolean]
156
- def read_primary?
157
- !@read_pool
158
- end
159
- alias :primary? :read_primary?
160
-
161
- # Close the connection to the database.
162
- def close
163
- super
164
- @read_pool = nil
165
- @secondary_pools.each do |pool|
166
- pool.close
167
- end
168
- @secondaries = []
169
- @secondary_pools = []
170
- @arbiters = []
171
- @nodes_tried = []
172
- @nodes_to_try = []
173
- end
174
-
175
- # If a ConnectionFailure is raised, this method will be called
176
- # to close the connection and reset connection values.
177
- # @deprecated
178
- def reset_connection
179
- close
180
- warn "ReplSetConnection#reset_connection is now deprecated. " +
181
- "Use ReplSetConnection#close instead."
182
- end
183
-
184
- # Is it okay to connect to a slave?
185
- #
186
- # @return [Boolean]
187
- def slave_ok?
188
- @read_secondary || @slave_ok
189
- end
190
-
191
- def authenticate_pools
192
- super
193
- @secondary_pools.each do |pool|
194
- pool.authenticate_existing
195
- end
196
- end
197
-
198
- def logout_pools(db)
199
- super
200
- @secondary_pools.each do |pool|
201
- pool.logout_existing(db)
202
- end
203
- end
204
-
205
- private
206
-
207
- def check_is_master(node)
208
- begin
209
- host, port = *node
210
- socket = TCPSocket.new(host, port)
211
- socket.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1)
212
-
213
- config = self['admin'].command({:ismaster => 1}, :socket => socket)
214
-
215
- check_set_name(config, socket)
216
- rescue OperationFailure, SocketError, SystemCallError, IOError => ex
217
- # It's necessary to rescue here. The #connect method will keep trying
218
- # until it has no more nodes to try and raise a ConnectionFailure if
219
- # it can't connect to a primary.
220
- ensure
221
- socket.close if socket
222
- @nodes_tried << node
223
-
224
- if config
225
- nodes = []
226
- nodes += config['hosts'] if config['hosts']
227
- nodes += config['arbiters'] if config['arbiters']
228
- nodes += config['passives'] if config['passives']
229
- update_node_list(nodes)
230
-
231
- if config['msg'] && @logger
232
- @logger.warn("MONGODB #{config['msg']}")
233
- end
234
- end
235
- end
236
-
237
- config
238
- end
239
-
240
- # Primary, when connecting to a replica can, can only be a true primary node.
241
- # (And not a slave, which is possible when connecting with the standard
242
- # Connection class.
243
- def is_primary?(config)
244
- config && (config['ismaster'] == 1 || config['ismaster'] == true)
245
- end
246
-
247
- # Pick a node randomly from the set of possible secondaries.
248
- def pick_secondary_for_read
249
- if (size = @secondary_pools.size) > 0
250
- @read_pool = @secondary_pools[rand(size)]
251
- end
252
- end
253
-
254
- # Make sure that we're connected to the expected replica set.
255
- def check_set_name(config, socket)
256
- if @replica_set
257
- config = self['admin'].command({:replSetGetStatus => 1},
258
- :socket => socket, :check_response => false)
259
-
260
- if !Mongo::Support.ok?(config)
261
- raise ReplicaSetConnectionError, config['errmsg']
262
- elsif config['set'] != @replica_set
263
- raise ReplicaSetConnectionError,
264
- "Attempting to connect to replica set '#{config['set']}' but expected '#{@replica_set}'"
265
- end
266
- end
267
- end
268
-
269
- # Determines what kind of node we have and caches its host
270
- # and port so that users can easily connect manually.
271
- def set_auxillary(node, config)
272
- if config
273
- if config['secondary']
274
- host, port = *node
275
- @secondaries << node unless @secondaries.include?(node)
276
- @secondary_pools << Pool.new(self, host, port, :size => @pool_size, :timeout => @timeout)
277
- elsif config['arbiterOnly']
278
- @arbiters << node unless @arbiters.include?(node)
279
- end
280
- end
281
- end
282
-
283
- # Update the list of known nodes. Only applies to replica sets,
284
- # where the response to the ismaster command will return a list
285
- # of known hosts.
286
- #
287
- # @param hosts [Array] a list of hosts, specified as string-encoded
288
- # host-port values. Example: ["myserver-1.org:27017", "myserver-1.org:27017"]
289
- #
290
- # @return [Array] the updated list of nodes
291
- def update_node_list(hosts)
292
- new_nodes = hosts.map do |host|
293
- if !host.respond_to?(:split)
294
- warn "Could not parse host #{host.inspect}."
295
- next
296
- end
297
-
298
- host, port = host.split(':')
299
- [host, port ? port.to_i : Connection::DEFAULT_PORT]
300
- end
301
-
302
- # Replace the list of seed nodes with the canonical list.
303
- @nodes = new_nodes.clone
304
-
305
- @nodes_to_try = new_nodes - @nodes_tried
306
- end
307
-
308
- # Checkout a socket for reading (i.e., a secondary node).
309
- def checkout_reader
310
- connect unless connected?
311
-
312
- if @read_pool
313
- @read_pool.checkout
314
- else
315
- checkout_writer
316
- end
317
- end
318
-
319
- # Checkout a socket for writing (i.e., a primary node).
320
- def checkout_writer
321
- connect unless connected?
322
-
323
- @primary_pool.checkout
324
- end
325
-
326
- # Checkin a socket used for reading.
327
- def checkin_reader(socket)
328
- if @read_pool
329
- @read_pool.checkin(socket)
330
- else
331
- checkin_writer(socket)
332
- end
333
- end
334
-
335
- # Checkin a socket used for writing.
336
- def checkin_writer(socket)
337
- if @primary_pool
338
- @primary_pool.checkin(socket)
339
- end
340
- end
341
- end
342
- end
data/lib/mongo/test.rb DELETED
@@ -1,20 +0,0 @@
1
-
2
- class Foo
3
-
4
- def zed
5
- puts "Foo"
6
- end
7
-
8
- end
9
-
10
- class Bar < Foo
11
-
12
- def zed(n=nil)
13
- if n.nil?
14
- puts "Bar"
15
- else
16
- super()
17
- end
18
- end
19
-
20
- end
@@ -1,177 +0,0 @@
1
- # encoding: UTF-8
2
-
3
- # --
4
- # Copyright (C) 2008-2011 10gen Inc.
5
- #
6
- # Licensed under the Apache License, Version 2.0 (the "License");
7
- # you may not use this file except in compliance with the License.
8
- # You may obtain a copy of the License at
9
- #
10
- # http://www.apache.org/licenses/LICENSE-2.0
11
- #
12
- # Unless required by applicable law or agreed to in writing, software
13
- # distributed under the License is distributed on an "AS IS" BASIS,
14
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
- # See the License for the specific language governing permissions and
16
- # limitations under the License.
17
-
18
- module Mongo
19
- class Pool
20
-
21
- attr_accessor :host, :port, :size, :timeout, :safe, :checked_out
22
-
23
- # Create a new pool of connections.
24
- #
25
- def initialize(connection, host, port, opts={})
26
- @connection = connection
27
-
28
- @host, @port = host, port
29
-
30
- # Pool size and timeout.
31
- @size = opts[:size] || 1
32
- @timeout = opts[:timeout] || 5.0
33
-
34
- # Mutex for synchronizing pool access
35
- @connection_mutex = Mutex.new
36
-
37
- # Condition variable for signal and wait
38
- @queue = ConditionVariable.new
39
-
40
- # Operations to perform on a socket
41
- @socket_ops = Hash.new { |h, k| h[k] = [] }
42
-
43
- @sockets = []
44
- @pids = {}
45
- @checked_out = []
46
- end
47
-
48
- def close
49
- @sockets.each do |sock|
50
- begin
51
- sock.close
52
- rescue IOError => ex
53
- warn "IOError when attempting to close socket connected to #{@host}:#{@port}: #{ex.inspect}"
54
- end
55
- end
56
- @host = @port = nil
57
- @sockets.clear
58
- @pids.clear
59
- @checked_out.clear
60
- end
61
-
62
- # Return a socket to the pool.
63
- def checkin(socket)
64
- @connection_mutex.synchronize do
65
- @checked_out.delete(socket)
66
- @queue.signal
67
- end
68
- true
69
- end
70
-
71
- # Adds a new socket to the pool and checks it out.
72
- #
73
- # This method is called exclusively from #checkout;
74
- # therefore, it runs within a mutex.
75
- def checkout_new_socket
76
- begin
77
- socket = TCPSocket.new(@host, @port)
78
- socket.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1)
79
- rescue => ex
80
- raise ConnectionFailure, "Failed to connect to host #{@host} and port #{@port}: #{ex}"
81
- end
82
-
83
- # If any saved authentications exist, we want to apply those
84
- # when creating new sockets.
85
- @connection.apply_saved_authentication(:socket => socket)
86
-
87
- @sockets << socket
88
- @pids[socket] = Process.pid
89
- @checked_out << socket
90
- socket
91
- end
92
-
93
- # If a user calls DB#authenticate, and several sockets exist,
94
- # then we need a way to apply the authentication on each socket.
95
- # So we store the apply_authentication method, and this will be
96
- # applied right before the next use of each socket.
97
- def authenticate_existing
98
- @connection_mutex.synchronize do
99
- @sockets.each do |socket|
100
- @socket_ops[socket] << Proc.new do
101
- @connection.apply_saved_authentication(:socket => socket)
102
- end
103
- end
104
- end
105
- end
106
-
107
- # Store the logout op for each existing socket to be applied before
108
- # the next use of each socket.
109
- def logout_existing(db)
110
- @connection_mutex.synchronize do
111
- @sockets.each do |socket|
112
- @socket_ops[socket] << Proc.new do
113
- @connection.db(db).issue_logout(:socket => socket)
114
- end
115
- end
116
- end
117
- end
118
-
119
- # Checks out the first available socket from the pool.
120
- #
121
- # If the pid has changed, remove the socket and check out
122
- # new one.
123
- #
124
- # This method is called exclusively from #checkout;
125
- # therefore, it runs within a mutex.
126
- def checkout_existing_socket
127
- socket = (@sockets - @checked_out).first
128
- if @pids[socket] != Process.pid
129
- @pids[socket] = nil
130
- @sockets.delete(socket)
131
- socket.close
132
- checkout_new_socket
133
- else
134
- @checked_out << socket
135
- socket
136
- end
137
- end
138
-
139
- # Check out an existing socket or create a new socket if the maximum
140
- # pool size has not been exceeded. Otherwise, wait for the next
141
- # available socket.
142
- def checkout
143
- @connection.connect if !@connection.connected?
144
- start_time = Time.now
145
- loop do
146
- if (Time.now - start_time) > @timeout
147
- raise ConnectionTimeoutError, "could not obtain connection within " +
148
- "#{@timeout} seconds. The max pool size is currently #{@size}; " +
149
- "consider increasing the pool size or timeout."
150
- end
151
-
152
- @connection_mutex.synchronize do
153
- socket = if @checked_out.size < @sockets.size
154
- checkout_existing_socket
155
- elsif @sockets.size < @size
156
- checkout_new_socket
157
- end
158
-
159
- if socket
160
-
161
- # This calls all procs, in order, scoped to existing sockets.
162
- # At the moment, we use this to lazily authenticate and
163
- # logout existing socket connections.
164
- @socket_ops[socket].reject! do |op|
165
- op.call
166
- end
167
-
168
- return socket
169
- else
170
- # Otherwise, wait
171
- @queue.wait(@connection_mutex)
172
- end
173
- end
174
- end
175
- end
176
- end
177
- end