square-activerecord 3.0.7

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 (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