square-activerecord 3.0.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (94) hide show
  1. data/CHANGELOG +6140 -0
  2. data/README.rdoc +222 -0
  3. data/examples/associations.png +0 -0
  4. data/examples/performance.rb +179 -0
  5. data/examples/simple.rb +14 -0
  6. data/lib/active_record.rb +124 -0
  7. data/lib/active_record/aggregations.rb +277 -0
  8. data/lib/active_record/association_preload.rb +430 -0
  9. data/lib/active_record/associations.rb +2307 -0
  10. data/lib/active_record/associations/association_collection.rb +572 -0
  11. data/lib/active_record/associations/association_proxy.rb +299 -0
  12. data/lib/active_record/associations/belongs_to_association.rb +91 -0
  13. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +82 -0
  14. data/lib/active_record/associations/has_and_belongs_to_many_association.rb +143 -0
  15. data/lib/active_record/associations/has_many_association.rb +128 -0
  16. data/lib/active_record/associations/has_many_through_association.rb +115 -0
  17. data/lib/active_record/associations/has_one_association.rb +143 -0
  18. data/lib/active_record/associations/has_one_through_association.rb +40 -0
  19. data/lib/active_record/associations/through_association_scope.rb +154 -0
  20. data/lib/active_record/attribute_methods.rb +60 -0
  21. data/lib/active_record/attribute_methods/before_type_cast.rb +30 -0
  22. data/lib/active_record/attribute_methods/dirty.rb +95 -0
  23. data/lib/active_record/attribute_methods/primary_key.rb +56 -0
  24. data/lib/active_record/attribute_methods/query.rb +39 -0
  25. data/lib/active_record/attribute_methods/read.rb +145 -0
  26. data/lib/active_record/attribute_methods/time_zone_conversion.rb +64 -0
  27. data/lib/active_record/attribute_methods/write.rb +43 -0
  28. data/lib/active_record/autosave_association.rb +369 -0
  29. data/lib/active_record/base.rb +1904 -0
  30. data/lib/active_record/callbacks.rb +284 -0
  31. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +364 -0
  32. data/lib/active_record/connection_adapters/abstract/connection_specification.rb +113 -0
  33. data/lib/active_record/connection_adapters/abstract/database_limits.rb +57 -0
  34. data/lib/active_record/connection_adapters/abstract/database_statements.rb +333 -0
  35. data/lib/active_record/connection_adapters/abstract/query_cache.rb +81 -0
  36. data/lib/active_record/connection_adapters/abstract/quoting.rb +73 -0
  37. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +739 -0
  38. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +539 -0
  39. data/lib/active_record/connection_adapters/abstract_adapter.rb +217 -0
  40. data/lib/active_record/connection_adapters/mysql_adapter.rb +657 -0
  41. data/lib/active_record/connection_adapters/postgresql_adapter.rb +1031 -0
  42. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +61 -0
  43. data/lib/active_record/connection_adapters/sqlite_adapter.rb +401 -0
  44. data/lib/active_record/counter_cache.rb +115 -0
  45. data/lib/active_record/dynamic_finder_match.rb +56 -0
  46. data/lib/active_record/dynamic_scope_match.rb +23 -0
  47. data/lib/active_record/errors.rb +172 -0
  48. data/lib/active_record/fixtures.rb +1006 -0
  49. data/lib/active_record/locale/en.yml +40 -0
  50. data/lib/active_record/locking/optimistic.rb +172 -0
  51. data/lib/active_record/locking/pessimistic.rb +55 -0
  52. data/lib/active_record/log_subscriber.rb +48 -0
  53. data/lib/active_record/migration.rb +617 -0
  54. data/lib/active_record/named_scope.rb +138 -0
  55. data/lib/active_record/nested_attributes.rb +419 -0
  56. data/lib/active_record/observer.rb +125 -0
  57. data/lib/active_record/persistence.rb +290 -0
  58. data/lib/active_record/query_cache.rb +36 -0
  59. data/lib/active_record/railtie.rb +91 -0
  60. data/lib/active_record/railties/controller_runtime.rb +38 -0
  61. data/lib/active_record/railties/databases.rake +512 -0
  62. data/lib/active_record/reflection.rb +411 -0
  63. data/lib/active_record/relation.rb +394 -0
  64. data/lib/active_record/relation/batches.rb +89 -0
  65. data/lib/active_record/relation/calculations.rb +295 -0
  66. data/lib/active_record/relation/finder_methods.rb +363 -0
  67. data/lib/active_record/relation/predicate_builder.rb +48 -0
  68. data/lib/active_record/relation/query_methods.rb +303 -0
  69. data/lib/active_record/relation/spawn_methods.rb +132 -0
  70. data/lib/active_record/schema.rb +59 -0
  71. data/lib/active_record/schema_dumper.rb +195 -0
  72. data/lib/active_record/serialization.rb +60 -0
  73. data/lib/active_record/serializers/xml_serializer.rb +244 -0
  74. data/lib/active_record/session_store.rb +340 -0
  75. data/lib/active_record/test_case.rb +67 -0
  76. data/lib/active_record/timestamp.rb +88 -0
  77. data/lib/active_record/transactions.rb +359 -0
  78. data/lib/active_record/validations.rb +84 -0
  79. data/lib/active_record/validations/associated.rb +48 -0
  80. data/lib/active_record/validations/uniqueness.rb +190 -0
  81. data/lib/active_record/version.rb +10 -0
  82. data/lib/rails/generators/active_record.rb +19 -0
  83. data/lib/rails/generators/active_record/migration.rb +15 -0
  84. data/lib/rails/generators/active_record/migration/migration_generator.rb +25 -0
  85. data/lib/rails/generators/active_record/migration/templates/migration.rb +17 -0
  86. data/lib/rails/generators/active_record/model/model_generator.rb +38 -0
  87. data/lib/rails/generators/active_record/model/templates/migration.rb +16 -0
  88. data/lib/rails/generators/active_record/model/templates/model.rb +5 -0
  89. data/lib/rails/generators/active_record/model/templates/module.rb +5 -0
  90. data/lib/rails/generators/active_record/observer/observer_generator.rb +15 -0
  91. data/lib/rails/generators/active_record/observer/templates/observer.rb +2 -0
  92. data/lib/rails/generators/active_record/session_migration/session_migration_generator.rb +24 -0
  93. data/lib/rails/generators/active_record/session_migration/templates/migration.rb +16 -0
  94. metadata +223 -0
@@ -0,0 +1,284 @@
1
+ require 'active_support/core_ext/array/wrap'
2
+
3
+ module ActiveRecord
4
+ # = Active Record Callbacks
5
+ #
6
+ # Callbacks are hooks into the life cycle of an Active Record object that allow you to trigger logic
7
+ # before or after an alteration of the object state. This can be used to make sure that associated and
8
+ # dependent objects are deleted when +destroy+ is called (by overwriting +before_destroy+) or to massage attributes
9
+ # before they're validated (by overwriting +before_validation+). As an example of the callbacks initiated, consider
10
+ # the <tt>Base#save</tt> call for a new record:
11
+ #
12
+ # * (-) <tt>save</tt>
13
+ # * (-) <tt>valid</tt>
14
+ # * (1) <tt>before_validation</tt>
15
+ # * (-) <tt>validate</tt>
16
+ # * (2) <tt>after_validation</tt>
17
+ # * (3) <tt>before_save</tt>
18
+ # * (4) <tt>before_create</tt>
19
+ # * (-) <tt>create</tt>
20
+ # * (5) <tt>after_create</tt>
21
+ # * (6) <tt>after_save</tt>
22
+ # * (7) <tt>after_commit</tt>
23
+ #
24
+ # Also, an <tt>after_rollback</tt> callback can be configured to be triggered whenever a rollback is issued.
25
+ # Check out <tt>ActiveRecord::Transactions</tt> for more details about <tt>after_commit</tt> and
26
+ # <tt>after_rollback</tt>.
27
+ #
28
+ # Lastly an <tt>after_find</tt> and <tt>after_initialize</tt> callback is triggered for each object that
29
+ # is found and instantiated by a finder, with <tt>after_initialize</tt> being triggered after new objects
30
+ # are instantiated as well.
31
+ #
32
+ # That's a total of twelve callbacks, which gives you immense power to react and prepare for each state in the
33
+ # Active Record life cycle. The sequence for calling <tt>Base#save</tt> for an existing record is similar,
34
+ # except that each <tt>_on_create</tt> callback is replaced by the corresponding <tt>_on_update</tt> callback.
35
+ #
36
+ # Examples:
37
+ # class CreditCard < ActiveRecord::Base
38
+ # # Strip everything but digits, so the user can specify "555 234 34" or
39
+ # # "5552-3434" or both will mean "55523434"
40
+ # before_validation(:on => :create) do
41
+ # self.number = number.gsub(/[^0-9]/, "") if attribute_present?("number")
42
+ # end
43
+ # end
44
+ #
45
+ # class Subscription < ActiveRecord::Base
46
+ # before_create :record_signup
47
+ #
48
+ # private
49
+ # def record_signup
50
+ # self.signed_up_on = Date.today
51
+ # end
52
+ # end
53
+ #
54
+ # class Firm < ActiveRecord::Base
55
+ # # Destroys the associated clients and people when the firm is destroyed
56
+ # before_destroy { |record| Person.destroy_all "firm_id = #{record.id}" }
57
+ # before_destroy { |record| Client.destroy_all "client_of = #{record.id}" }
58
+ # end
59
+ #
60
+ # == Inheritable callback queues
61
+ #
62
+ # Besides the overwritable callback methods, it's also possible to register callbacks through the
63
+ # use of the callback macros. Their main advantage is that the macros add behavior into a callback
64
+ # queue that is kept intact down through an inheritance hierarchy.
65
+ #
66
+ # class Topic < ActiveRecord::Base
67
+ # before_destroy :destroy_author
68
+ # end
69
+ #
70
+ # class Reply < Topic
71
+ # before_destroy :destroy_readers
72
+ # end
73
+ #
74
+ # Now, when <tt>Topic#destroy</tt> is run only +destroy_author+ is called. When <tt>Reply#destroy</tt> is
75
+ # run, both +destroy_author+ and +destroy_readers+ are called. Contrast this to the following situation
76
+ # where the +before_destroy+ methis is overriden:
77
+ #
78
+ # class Topic < ActiveRecord::Base
79
+ # def before_destroy() destroy_author end
80
+ # end
81
+ #
82
+ # class Reply < Topic
83
+ # def before_destroy() destroy_readers end
84
+ # end
85
+ #
86
+ # In that case, <tt>Reply#destroy</tt> would only run +destroy_readers+ and _not_ +destroy_author+.
87
+ # So, use the callback macros when you want to ensure that a certain callback is called for the entire
88
+ # hierarchy, and use the regular overwriteable methods when you want to leave it up to each descendant
89
+ # to decide whether they want to call +super+ and trigger the inherited callbacks.
90
+ #
91
+ # *IMPORTANT:* In order for inheritance to work for the callback queues, you must specify the
92
+ # callbacks before specifying the associations. Otherwise, you might trigger the loading of a
93
+ # child before the parent has registered the callbacks and they won't be inherited.
94
+ #
95
+ # == Types of callbacks
96
+ #
97
+ # There are four types of callbacks accepted by the callback macros: Method references (symbol), callback objects,
98
+ # inline methods (using a proc), and inline eval methods (using a string). Method references and callback objects
99
+ # are the recommended approaches, inline methods using a proc are sometimes appropriate (such as for
100
+ # creating mix-ins), and inline eval methods are deprecated.
101
+ #
102
+ # The method reference callbacks work by specifying a protected or private method available in the object, like this:
103
+ #
104
+ # class Topic < ActiveRecord::Base
105
+ # before_destroy :delete_parents
106
+ #
107
+ # private
108
+ # def delete_parents
109
+ # self.class.delete_all "parent_id = #{id}"
110
+ # end
111
+ # end
112
+ #
113
+ # The callback objects have methods named after the callback called with the record as the only parameter, such as:
114
+ #
115
+ # class BankAccount < ActiveRecord::Base
116
+ # before_save EncryptionWrapper.new
117
+ # after_save EncryptionWrapper.new
118
+ # after_initialize EncryptionWrapper.new
119
+ # end
120
+ #
121
+ # class EncryptionWrapper
122
+ # def before_save(record)
123
+ # record.credit_card_number = encrypt(record.credit_card_number)
124
+ # end
125
+ #
126
+ # def after_save(record)
127
+ # record.credit_card_number = decrypt(record.credit_card_number)
128
+ # end
129
+ #
130
+ # alias_method :after_find, :after_save
131
+ #
132
+ # private
133
+ # def encrypt(value)
134
+ # # Secrecy is committed
135
+ # end
136
+ #
137
+ # def decrypt(value)
138
+ # # Secrecy is unveiled
139
+ # end
140
+ # end
141
+ #
142
+ # So you specify the object you want messaged on a given callback. When that callback is triggered, the object has
143
+ # a method by the name of the callback messaged. You can make these callbacks more flexible by passing in other
144
+ # initialization data such as the name of the attribute to work with:
145
+ #
146
+ # class BankAccount < ActiveRecord::Base
147
+ # before_save EncryptionWrapper.new("credit_card_number")
148
+ # after_save EncryptionWrapper.new("credit_card_number")
149
+ # after_initialize EncryptionWrapper.new("credit_card_number")
150
+ # end
151
+ #
152
+ # class EncryptionWrapper
153
+ # def initialize(attribute)
154
+ # @attribute = attribute
155
+ # end
156
+ #
157
+ # def before_save(record)
158
+ # record.send("#{@attribute}=", encrypt(record.send("#{@attribute}")))
159
+ # end
160
+ #
161
+ # def after_save(record)
162
+ # record.send("#{@attribute}=", decrypt(record.send("#{@attribute}")))
163
+ # end
164
+ #
165
+ # alias_method :after_find, :after_save
166
+ #
167
+ # private
168
+ # def encrypt(value)
169
+ # # Secrecy is committed
170
+ # end
171
+ #
172
+ # def decrypt(value)
173
+ # # Secrecy is unveiled
174
+ # end
175
+ # end
176
+ #
177
+ # The callback macros usually accept a symbol for the method they're supposed to run, but you can also
178
+ # pass a "method string", which will then be evaluated within the binding of the callback. Example:
179
+ #
180
+ # class Topic < ActiveRecord::Base
181
+ # before_destroy 'self.class.delete_all "parent_id = #{id}"'
182
+ # end
183
+ #
184
+ # Notice that single quotes (') are used so the <tt>#{id}</tt> part isn't evaluated until the callback
185
+ # is triggered. Also note that these inline callbacks can be stacked just like the regular ones:
186
+ #
187
+ # class Topic < ActiveRecord::Base
188
+ # before_destroy 'self.class.delete_all "parent_id = #{id}"',
189
+ # 'puts "Evaluated after parents are destroyed"'
190
+ # end
191
+ #
192
+ # == <tt>before_validation*</tt> returning statements
193
+ #
194
+ # If the returning value of a +before_validation+ callback can be evaluated to +false+, the process will be
195
+ # aborted and <tt>Base#save</tt> will return +false+. If Base#save! is called it will raise a
196
+ # ActiveRecord::RecordInvalid exception. Nothing will be appended to the errors object.
197
+ #
198
+ # == Canceling callbacks
199
+ #
200
+ # If a <tt>before_*</tt> callback returns +false+, all the later callbacks and the associated action are
201
+ # cancelled. If an <tt>after_*</tt> callback returns +false+, all the later callbacks are cancelled.
202
+ # Callbacks are generally run in the order they are defined, with the exception of callbacks defined as
203
+ # methods on the model, which are called last.
204
+ #
205
+ # == Transactions
206
+ #
207
+ # The entire callback chain of a +save+, <tt>save!</tt>, or +destroy+ call runs
208
+ # within a transaction. That includes <tt>after_*</tt> hooks. If everything
209
+ # goes fine a COMMIT is executed once the chain has been completed.
210
+ #
211
+ # If a <tt>before_*</tt> callback cancels the action a ROLLBACK is issued. You
212
+ # can also trigger a ROLLBACK raising an exception in any of the callbacks,
213
+ # including <tt>after_*</tt> hooks. Note, however, that in that case the client
214
+ # needs to be aware of it because an ordinary +save+ will raise such exception
215
+ # instead of quietly returning +false+.
216
+ #
217
+ # == Debugging callbacks
218
+ #
219
+ # To list the methods and procs registered with a particular callback, append <tt>_callback_chain</tt> to
220
+ # the callback name that you wish to list and send that to your class from the Rails console:
221
+ #
222
+ # >> Topic.after_save_callback_chain
223
+ # => [#<ActiveSupport::Callbacks::Callback:0x3f6a448
224
+ # @method=#<Proc:0x03f9a42c@/Users/foo/bar/app/models/topic.rb:43>, kind:after_save, identifiernil,
225
+ # options{}]
226
+ #
227
+ module Callbacks
228
+ extend ActiveSupport::Concern
229
+
230
+ CALLBACKS = [
231
+ :after_initialize, :after_find, :after_touch, :before_validation, :after_validation,
232
+ :before_save, :around_save, :after_save, :before_create, :around_create,
233
+ :after_create, :before_update, :around_update, :after_update,
234
+ :before_destroy, :around_destroy, :after_destroy, :after_commit, :after_rollback
235
+ ]
236
+
237
+ included do
238
+ extend ActiveModel::Callbacks
239
+ include ActiveModel::Validations::Callbacks
240
+
241
+ define_model_callbacks :initialize, :find, :touch, :only => :after
242
+ define_model_callbacks :save, :create, :update, :destroy
243
+ end
244
+
245
+ module ClassMethods
246
+ def method_added(meth)
247
+ super
248
+ if CALLBACKS.include?(meth.to_sym)
249
+ ActiveSupport::Deprecation.warn("Base##{meth} has been deprecated, please use Base.#{meth} :method instead", caller[0,1])
250
+ send(meth.to_sym, meth.to_sym)
251
+ end
252
+ end
253
+ end
254
+
255
+ def destroy #:nodoc:
256
+ _run_destroy_callbacks { super }
257
+ end
258
+
259
+ def touch(*) #:nodoc:
260
+ _run_touch_callbacks { super }
261
+ end
262
+
263
+ def deprecated_callback_method(symbol) #:nodoc:
264
+ if respond_to?(symbol, true)
265
+ ActiveSupport::Deprecation.warn("Overwriting #{symbol} in your models has been deprecated, please use Base##{symbol} :method_name instead")
266
+ send(symbol)
267
+ end
268
+ end
269
+
270
+ private
271
+
272
+ def create_or_update #:nodoc:
273
+ _run_save_callbacks { super }
274
+ end
275
+
276
+ def create #:nodoc:
277
+ _run_create_callbacks { super }
278
+ end
279
+
280
+ def update(*) #:nodoc:
281
+ _run_update_callbacks { super }
282
+ end
283
+ end
284
+ end
@@ -0,0 +1,364 @@
1
+ require 'thread'
2
+ require 'monitor'
3
+ require 'set'
4
+ require 'active_support/core_ext/module/synchronization'
5
+
6
+ module ActiveRecord
7
+ # Raised when a connection could not be obtained within the connection
8
+ # acquisition timeout period.
9
+ class ConnectionTimeoutError < ConnectionNotEstablished
10
+ end
11
+
12
+ module ConnectionAdapters
13
+ # Connection pool base class for managing Active Record database
14
+ # connections.
15
+ #
16
+ # == Introduction
17
+ #
18
+ # A connection pool synchronizes thread access to a limited number of
19
+ # database connections. The basic idea is that each thread checks out a
20
+ # database connection from the pool, uses that connection, and checks the
21
+ # connection back in. ConnectionPool is completely thread-safe, and will
22
+ # ensure that a connection cannot be used by two threads at the same time,
23
+ # as long as ConnectionPool's contract is correctly followed. It will also
24
+ # handle cases in which there are more threads than connections: if all
25
+ # connections have been checked out, and a thread tries to checkout a
26
+ # connection anyway, then ConnectionPool will wait until some other thread
27
+ # has checked in a connection.
28
+ #
29
+ # == Obtaining (checking out) a connection
30
+ #
31
+ # Connections can be obtained and used from a connection pool in several
32
+ # ways:
33
+ #
34
+ # 1. Simply use ActiveRecord::Base.connection as with Active Record 2.1 and
35
+ # earlier (pre-connection-pooling). Eventually, when you're done with
36
+ # the connection(s) and wish it to be returned to the pool, you call
37
+ # ActiveRecord::Base.clear_active_connections!. This will be the
38
+ # default behavior for Active Record when used in conjunction with
39
+ # Action Pack's request handling cycle.
40
+ # 2. Manually check out a connection from the pool with
41
+ # ActiveRecord::Base.connection_pool.checkout. You are responsible for
42
+ # returning this connection to the pool when finished by calling
43
+ # ActiveRecord::Base.connection_pool.checkin(connection).
44
+ # 3. Use ActiveRecord::Base.connection_pool.with_connection(&block), which
45
+ # obtains a connection, yields it as the sole argument to the block,
46
+ # and returns it to the pool after the block completes.
47
+ #
48
+ # Connections in the pool are actually AbstractAdapter objects (or objects
49
+ # compatible with AbstractAdapter's interface).
50
+ #
51
+ # == Options
52
+ #
53
+ # There are two connection-pooling-related options that you can add to
54
+ # your database connection configuration:
55
+ #
56
+ # * +pool+: number indicating size of connection pool (default 5)
57
+ # * +wait_timeout+: number of seconds to block and wait for a connection
58
+ # before giving up and raising a timeout error (default 5 seconds).
59
+ class ConnectionPool
60
+ attr_reader :spec, :connections
61
+
62
+ # Creates a new ConnectionPool object. +spec+ is a ConnectionSpecification
63
+ # object which describes database connection information (e.g. adapter,
64
+ # host name, username, password, etc), as well as the maximum size for
65
+ # this ConnectionPool.
66
+ #
67
+ # The default ConnectionPool maximum size is 5.
68
+ def initialize(spec)
69
+ @spec = spec
70
+
71
+ # The cache of reserved connections mapped to threads
72
+ @reserved_connections = {}
73
+
74
+ # The mutex used to synchronize pool access
75
+ @connection_mutex = Monitor.new
76
+ @queue = @connection_mutex.new_cond
77
+
78
+ # default 5 second timeout unless on ruby 1.9
79
+ @timeout = spec.config[:wait_timeout] || 5
80
+
81
+ # default max pool size to 5
82
+ @size = (spec.config[:pool] && spec.config[:pool].to_i) || 5
83
+
84
+ @connections = []
85
+ @checked_out = []
86
+ end
87
+
88
+ # Retrieve the connection associated with the current thread, or call
89
+ # #checkout to obtain one if necessary.
90
+ #
91
+ # #connection can be called any number of times; the connection is
92
+ # held in a hash keyed by the thread id.
93
+ def connection
94
+ @reserved_connections[current_connection_id] ||= checkout
95
+ end
96
+
97
+ # Signal that the thread is finished with the current connection.
98
+ # #release_connection releases the connection-thread association
99
+ # and returns the connection to the pool.
100
+ def release_connection(with_id = current_connection_id)
101
+ conn = @reserved_connections.delete(with_id)
102
+ checkin conn if conn
103
+ end
104
+
105
+ # If a connection already exists yield it to the block. If no connection
106
+ # exists checkout a connection, yield it to the block, and checkin the
107
+ # connection when finished.
108
+ def with_connection
109
+ connection_id = current_connection_id
110
+ fresh_connection = true unless @reserved_connections[connection_id]
111
+ yield connection
112
+ ensure
113
+ release_connection(connection_id) if fresh_connection
114
+ end
115
+
116
+ # Returns true if a connection has already been opened.
117
+ def connected?
118
+ !@connections.empty?
119
+ end
120
+
121
+ # Disconnects all connections in the pool, and clears the pool.
122
+ def disconnect!
123
+ @reserved_connections.each do |name,conn|
124
+ checkin conn
125
+ end
126
+ @reserved_connections = {}
127
+ @connections.each do |conn|
128
+ conn.disconnect!
129
+ end
130
+ @connections = []
131
+ end
132
+
133
+ # Clears the cache which maps classes
134
+ def clear_reloadable_connections!
135
+ @reserved_connections.each do |name, conn|
136
+ checkin conn
137
+ end
138
+ @reserved_connections = {}
139
+ @connections.each do |conn|
140
+ conn.disconnect! if conn.requires_reloading?
141
+ end
142
+ @connections.delete_if do |conn|
143
+ conn.requires_reloading?
144
+ end
145
+ end
146
+
147
+ # Verify active connections and remove and disconnect connections
148
+ # associated with stale threads.
149
+ def verify_active_connections! #:nodoc:
150
+ clear_stale_cached_connections!
151
+ @connections.each do |connection|
152
+ connection.verify!
153
+ end
154
+ end
155
+
156
+ # Return any checked-out connections back to the pool by threads that
157
+ # are no longer alive.
158
+ def clear_stale_cached_connections!
159
+ keys = @reserved_connections.keys - Thread.list.find_all { |t|
160
+ t.alive?
161
+ }.map { |thread| thread.object_id }
162
+ keys.each do |key|
163
+ checkin @reserved_connections[key]
164
+ @reserved_connections.delete(key)
165
+ end
166
+ end
167
+
168
+ # Check-out a database connection from the pool, indicating that you want
169
+ # to use it. You should call #checkin when you no longer need this.
170
+ #
171
+ # This is done by either returning an existing connection, or by creating
172
+ # a new connection. If the maximum number of connections for this pool has
173
+ # already been reached, but the pool is empty (i.e. they're all being used),
174
+ # then this method will wait until a thread has checked in a connection.
175
+ # The wait time is bounded however: if no connection can be checked out
176
+ # within the timeout specified for this pool, then a ConnectionTimeoutError
177
+ # exception will be raised.
178
+ #
179
+ # Returns: an AbstractAdapter object.
180
+ #
181
+ # Raises:
182
+ # - ConnectionTimeoutError: no connection can be obtained from the pool
183
+ # within the timeout period.
184
+ def checkout
185
+ # Checkout an available connection
186
+ @connection_mutex.synchronize do
187
+ loop do
188
+ conn = if @checked_out.size < @connections.size
189
+ checkout_existing_connection
190
+ elsif @connections.size < @size
191
+ checkout_new_connection
192
+ end
193
+ return conn if conn
194
+
195
+ @queue.wait(@timeout)
196
+
197
+ if(@checked_out.size < @connections.size)
198
+ next
199
+ else
200
+ clear_stale_cached_connections!
201
+ if @size == @checked_out.size
202
+ raise ConnectionTimeoutError, "could not obtain a database connection#{" within #{@timeout} seconds" if @timeout}. The max pool size is currently #{@size}; consider increasing it."
203
+ end
204
+ end
205
+
206
+ end
207
+ end
208
+ end
209
+
210
+ # Check-in a database connection back into the pool, indicating that you
211
+ # no longer need this connection.
212
+ #
213
+ # +conn+: an AbstractAdapter object, which was obtained by earlier by
214
+ # calling +checkout+ on this pool.
215
+ def checkin(conn)
216
+ @connection_mutex.synchronize do
217
+ conn.send(:_run_checkin_callbacks) do
218
+ @checked_out.delete conn
219
+ @queue.signal
220
+ end
221
+ end
222
+ end
223
+
224
+ synchronize :clear_reloadable_connections!, :verify_active_connections!,
225
+ :connected?, :disconnect!, :with => :@connection_mutex
226
+
227
+ private
228
+ def new_connection
229
+ ActiveRecord::Base.send(spec.adapter_method, spec.config)
230
+ end
231
+
232
+ def current_connection_id #:nodoc:
233
+ Thread.current.object_id
234
+ end
235
+
236
+ def checkout_new_connection
237
+ c = new_connection
238
+ @connections << c
239
+ checkout_and_verify(c)
240
+ end
241
+
242
+ def checkout_existing_connection
243
+ c = (@connections - @checked_out).first
244
+ checkout_and_verify(c)
245
+ end
246
+
247
+ def checkout_and_verify(c)
248
+ c.run_callbacks :checkout do
249
+ c.verify!
250
+ @checked_out << c
251
+ end
252
+ c
253
+ end
254
+ end
255
+
256
+ # ConnectionHandler is a collection of ConnectionPool objects. It is used
257
+ # for keeping separate connection pools for Active Record models that connect
258
+ # to different databases.
259
+ #
260
+ # For example, suppose that you have 5 models, with the following hierarchy:
261
+ #
262
+ # |
263
+ # +-- Book
264
+ # | |
265
+ # | +-- ScaryBook
266
+ # | +-- GoodBook
267
+ # +-- Author
268
+ # +-- BankAccount
269
+ #
270
+ # Suppose that Book is to connect to a separate database (i.e. one other
271
+ # than the default database). Then Book, ScaryBook and GoodBook will all use
272
+ # the same connection pool. Likewise, Author and BankAccount will use the
273
+ # same connection pool. However, the connection pool used by Author/BankAccount
274
+ # is not the same as the one used by Book/ScaryBook/GoodBook.
275
+ #
276
+ # Normally there is only a single ConnectionHandler instance, accessible via
277
+ # ActiveRecord::Base.connection_handler. Active Record models use this to
278
+ # determine that connection pool that they should use.
279
+ class ConnectionHandler
280
+ attr_reader :connection_pools
281
+
282
+ def initialize(pools = {})
283
+ @connection_pools = pools
284
+ end
285
+
286
+ def establish_connection(name, spec)
287
+ @connection_pools[name] = ConnectionAdapters::ConnectionPool.new(spec)
288
+ end
289
+
290
+ # Returns any connections in use by the current thread back to the pool,
291
+ # and also returns connections to the pool cached by threads that are no
292
+ # longer alive.
293
+ def clear_active_connections!
294
+ @connection_pools.each_value {|pool| pool.release_connection }
295
+ end
296
+
297
+ # Clears the cache which maps classes
298
+ def clear_reloadable_connections!
299
+ @connection_pools.each_value {|pool| pool.clear_reloadable_connections! }
300
+ end
301
+
302
+ def clear_all_connections!
303
+ @connection_pools.each_value {|pool| pool.disconnect! }
304
+ end
305
+
306
+ # Verify active connections.
307
+ def verify_active_connections! #:nodoc:
308
+ @connection_pools.each_value {|pool| pool.verify_active_connections! }
309
+ end
310
+
311
+ # Locate the connection of the nearest super class. This can be an
312
+ # active or defined connection: if it is the latter, it will be
313
+ # opened and set as the active connection for the class it was defined
314
+ # for (not necessarily the current class).
315
+ def retrieve_connection(klass) #:nodoc:
316
+ pool = retrieve_connection_pool(klass)
317
+ (pool && pool.connection) or raise ConnectionNotEstablished
318
+ end
319
+
320
+ # Returns true if a connection that's accessible to this class has
321
+ # already been opened.
322
+ def connected?(klass)
323
+ conn = retrieve_connection_pool(klass)
324
+ conn && conn.connected?
325
+ end
326
+
327
+ # Remove the connection for this class. This will close the active
328
+ # connection and the defined connection (if they exist). The result
329
+ # can be used as an argument for establish_connection, for easily
330
+ # re-establishing the connection.
331
+ def remove_connection(klass)
332
+ pool = @connection_pools[klass.name]
333
+ return nil unless pool
334
+
335
+ @connection_pools.delete_if { |key, value| value == pool }
336
+ pool.disconnect!
337
+ pool.spec.config
338
+ end
339
+
340
+ def retrieve_connection_pool(klass)
341
+ pool = @connection_pools[klass.name]
342
+ return pool if pool
343
+ return nil if ActiveRecord::Base == klass
344
+ retrieve_connection_pool klass.superclass
345
+ end
346
+ end
347
+
348
+ class ConnectionManagement
349
+ def initialize(app)
350
+ @app = app
351
+ end
352
+
353
+ def call(env)
354
+ @app.call(env)
355
+ ensure
356
+ # Don't return connection (and perform implicit rollback) if
357
+ # this request is a part of integration test
358
+ unless env.key?("rack.test")
359
+ ActiveRecord::Base.clear_active_connections!
360
+ end
361
+ end
362
+ end
363
+ end
364
+ end