advanced_connection 0.5.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (88) hide show
  1. checksums.yaml +7 -0
  2. data/.document +5 -0
  3. data/.gitignore +8 -0
  4. data/.rspec +2 -0
  5. data/.travis.yml +63 -0
  6. data/Gemfile +3 -0
  7. data/Gemfile.lock +218 -0
  8. data/MIT-LICENSE +20 -0
  9. data/README.rdoc +3 -0
  10. data/Rakefile +165 -0
  11. data/advanced_connection.gemspec +49 -0
  12. data/gemfiles/jruby/rails4_1.gemfile +7 -0
  13. data/gemfiles/jruby/rails4_2.gemfile +7 -0
  14. data/gemfiles/ruby/rails4_1.gemfile +7 -0
  15. data/gemfiles/ruby/rails4_2.gemfile +7 -0
  16. data/lib/advanced_connection/active_record_ext/abstract_adapter/statement_pooling.rb +121 -0
  17. data/lib/advanced_connection/active_record_ext/abstract_adapter.rb +48 -0
  18. data/lib/advanced_connection/active_record_ext/connection_pool/idle_manager.rb +271 -0
  19. data/lib/advanced_connection/active_record_ext/connection_pool/queues.rb +60 -0
  20. data/lib/advanced_connection/active_record_ext/connection_pool/statement_pooling.rb +42 -0
  21. data/lib/advanced_connection/active_record_ext/connection_pool/without_connection.rb +93 -0
  22. data/lib/advanced_connection/active_record_ext/connection_pool.rb +38 -0
  23. data/lib/advanced_connection/active_record_ext/without_connection.rb +30 -0
  24. data/lib/advanced_connection/active_record_ext.rb +59 -0
  25. data/lib/advanced_connection/config.rb +247 -0
  26. data/lib/advanced_connection/error.rb +27 -0
  27. data/lib/advanced_connection/railtie.rb +40 -0
  28. data/lib/advanced_connection/version.rb +29 -0
  29. data/lib/advanced_connection.rb +65 -0
  30. data/lib/generators/advanced_connection/install/USAGE +5 -0
  31. data/lib/generators/advanced_connection/install/install_generator.rb +30 -0
  32. data/lib/generators/advanced_connection/install/templates/advanced_connection.rb +142 -0
  33. data/lib/tasks/advanced_connection_tasks.rake +25 -0
  34. data/spec/config/database.yml +18 -0
  35. data/spec/config/database.yml.erb +54 -0
  36. data/spec/dummy/.gitignore +1 -0
  37. data/spec/dummy/README.rdoc +28 -0
  38. data/spec/dummy/Rakefile +6 -0
  39. data/spec/dummy/app/assets/images/.keep +0 -0
  40. data/spec/dummy/app/assets/javascripts/application.js +13 -0
  41. data/spec/dummy/app/assets/stylesheets/application.css +15 -0
  42. data/spec/dummy/app/controllers/application_controller.rb +5 -0
  43. data/spec/dummy/app/controllers/concerns/.keep +0 -0
  44. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  45. data/spec/dummy/app/mailers/.keep +0 -0
  46. data/spec/dummy/app/models/.keep +0 -0
  47. data/spec/dummy/app/models/book.rb +2 -0
  48. data/spec/dummy/app/models/concerns/.keep +0 -0
  49. data/spec/dummy/app/views/layouts/application.html.erb +13 -0
  50. data/spec/dummy/bin/bundle +3 -0
  51. data/spec/dummy/bin/rails +4 -0
  52. data/spec/dummy/bin/rake +4 -0
  53. data/spec/dummy/bin/setup +29 -0
  54. data/spec/dummy/config/application.rb +32 -0
  55. data/spec/dummy/config/boot.rb +5 -0
  56. data/spec/dummy/config/database.yml +17 -0
  57. data/spec/dummy/config/environment.rb +5 -0
  58. data/spec/dummy/config/environments/development.rb +48 -0
  59. data/spec/dummy/config/environments/production.rb +79 -0
  60. data/spec/dummy/config/environments/test.rb +42 -0
  61. data/spec/dummy/config/initializers/advanced_connection.rb +142 -0
  62. data/spec/dummy/config/initializers/assets.rb +11 -0
  63. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  64. data/spec/dummy/config/initializers/cookies_serializer.rb +3 -0
  65. data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  66. data/spec/dummy/config/initializers/inflections.rb +16 -0
  67. data/spec/dummy/config/initializers/mime_types.rb +4 -0
  68. data/spec/dummy/config/initializers/session_store.rb +3 -0
  69. data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
  70. data/spec/dummy/config/locales/en.yml +23 -0
  71. data/spec/dummy/config/routes.rb +56 -0
  72. data/spec/dummy/config/secrets.yml +22 -0
  73. data/spec/dummy/config.ru +4 -0
  74. data/spec/dummy/db/migrate/20160222045238_create_books.rb +10 -0
  75. data/spec/dummy/db/schema.rb +23 -0
  76. data/spec/dummy/lib/assets/.keep +0 -0
  77. data/spec/dummy/log/.keep +0 -0
  78. data/spec/dummy/log/test.log +327 -0
  79. data/spec/dummy/public/404.html +67 -0
  80. data/spec/dummy/public/422.html +67 -0
  81. data/spec/dummy/public/500.html +66 -0
  82. data/spec/dummy/public/favicon.ico +0 -0
  83. data/spec/dummy/test/fixtures/books.yml +9 -0
  84. data/spec/dummy/test/models/book_test.rb +7 -0
  85. data/spec/idle_manager_spec.rb +16 -0
  86. data/spec/spec_helper.rb +25 -0
  87. data/spec/support/db_config.rb +61 -0
  88. metadata +399 -0
@@ -0,0 +1,60 @@
1
+ #
2
+ # Copyright (C) 2016 Finalsite, LLC
3
+ # Copyright (C) 2016 Carl P. Corliss <carl.corliss@finalsite.com>
4
+ #
5
+ # Permission is hereby granted, free of charge, to any person obtaining a copy of
6
+ # this software and associated documentation files (the "Software"), to deal in
7
+ # the Software without restriction, including without limitation the rights to
8
+ # use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9
+ # the Software, and to permit persons to whom the Software is furnished to do so,
10
+ # subject to the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be included in all
13
+ # copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17
+ # FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18
+ # COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19
+ # IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20
+ # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
+ #
22
+ module AdvancedConnection::ActiveRecordExt
23
+ module ConnectionPool
24
+ module Queues
25
+ class Default < ActiveRecord::ConnectionAdapters::ConnectionPool::Queue
26
+ def size
27
+ synchronize { @queue.size }
28
+ end
29
+ end
30
+ FIFO = Queues
31
+
32
+ class Stack < Default
33
+ def remove
34
+ @queue.pop
35
+ end
36
+ end
37
+
38
+ class AgeSorted < Default
39
+ def poll(timeout = nil)
40
+ synchronize do
41
+ @queue.sort_by!(&:instance_age)
42
+ no_wait_poll || (timeout && wait_poll(timeout))
43
+ end
44
+ end
45
+ end
46
+
47
+ class YoungAgeBiased < AgeSorted
48
+ def remove
49
+ @queue.pop
50
+ end
51
+ end
52
+
53
+ class OldAgeBiased < AgeSorted
54
+ def remove
55
+ @queue.shift
56
+ end
57
+ end
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,42 @@
1
+ #
2
+ # Copyright (C) 2016 Finalsite, LLC
3
+ # Copyright (C) 2016 Carl P. Corliss <carl.corliss@finalsite.com>
4
+ #
5
+ # Permission is hereby granted, free of charge, to any person obtaining a copy of
6
+ # this software and associated documentation files (the "Software"), to deal in
7
+ # the Software without restriction, including without limitation the rights to
8
+ # use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9
+ # the Software, and to permit persons to whom the Software is furnished to do so,
10
+ # subject to the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be included in all
13
+ # copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17
+ # FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18
+ # COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19
+ # IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20
+ # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
+ #
22
+ module AdvancedConnection::ActiveRecordExt
23
+ module ConnectionPool
24
+ module StatementPooling
25
+ extend ActiveSupport::Concern
26
+
27
+ included do
28
+ alias_method_chain :new_connection, :statement_pooling
29
+ end
30
+
31
+ def new_connection_with_statement_pooling
32
+ new_connection_without_statement_pooling.tap { |conn|
33
+ unless conn.respond_to? :around_connection_checkin
34
+ conn.class.instance_exec {
35
+ include AbstractAdapter::StatementPooling
36
+ }
37
+ end
38
+ }
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,93 @@
1
+ #
2
+ # Copyright (C) 2016 Finalsite, LLC
3
+ # Copyright (C) 2016 Carl P. Corliss <carl.corliss@finalsite.com>
4
+ #
5
+ # Permission is hereby granted, free of charge, to any person obtaining a copy of
6
+ # this software and associated documentation files (the "Software"), to deal in
7
+ # the Software without restriction, including without limitation the rights to
8
+ # use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9
+ # the Software, and to permit persons to whom the Software is furnished to do so,
10
+ # subject to the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be included in all
13
+ # copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17
+ # FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18
+ # COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19
+ # IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20
+ # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
+ #
22
+ module AdvancedConnection::ActiveRecordExt
23
+ module ConnectionPool
24
+ module WithoutConnection
25
+ extend ActiveSupport::Concern
26
+
27
+ included do
28
+ include ::ActiveSupport::Callbacks
29
+ alias_method :retrieve_connection, :connection
30
+
31
+ define_callbacks :without_connection
32
+ set_callback :without_connection, :around, :around_without_connection
33
+ set_callback :without_connection, :before, :before_without_connection
34
+ set_callback :without_connection, :after, :after_without_connection
35
+ end
36
+
37
+ def without_connection
38
+ return unless block_given?
39
+
40
+ if AdvancedConnection.callbacks.without_connection.present?
41
+ run_callbacks(:without_connection) do
42
+ __without_connection() { yield }
43
+ end
44
+ else
45
+ __without_connection() { yield }
46
+ end
47
+ end
48
+
49
+ private
50
+
51
+ def __without_connection
52
+ begin
53
+ # return the connection to the pool for the duration of `yield`
54
+ release_connection if active_connection?
55
+ raise Error::UnableToReleaseConnection if active_connection?
56
+ yield
57
+ ensure
58
+ tries = 3
59
+ begin
60
+ # attempt to retrieve another connection
61
+ retrieve_connection
62
+ rescue ActiveRecord::ConnectionTimeoutError
63
+ Rails.logger.info "Failed to acquire a connection (#{Thread.current.object_id}) trying #{tries > 1 ? "#{tries} more times" : 'once more'}"
64
+ retry unless (tries -= 1) < 0
65
+ Rails.logger.info "Giving up on trying to acquire another connection"
66
+ raise
67
+ end
68
+ end
69
+ end
70
+
71
+ def around_without_connection(&block)
72
+ callbacks = AdvancedConnection.callbacks.without_connection
73
+ if callbacks.around.respond_to? :call
74
+ callbacks.around.call() { block.call }
75
+ end
76
+ end
77
+
78
+ def before_without_connection
79
+ callbacks = AdvancedConnection.callbacks.without_connection
80
+ if callbacks.before.respond_to? :call
81
+ callbacks.before.call
82
+ end
83
+ end
84
+
85
+ def after_without_connection
86
+ callbacks = AdvancedConnection.callbacks.without_connection
87
+ if callbacks.after.respond_to? :call
88
+ callbacks.after.call
89
+ end
90
+ end
91
+ end
92
+ end
93
+ end
@@ -0,0 +1,38 @@
1
+ #
2
+ # Copyright (C) 2016 Finalsite, LLC
3
+ # Copyright (C) 2016 Carl P. Corliss <carl.corliss@finalsite.com>
4
+ #
5
+ # Permission is hereby granted, free of charge, to any person obtaining a copy of
6
+ # this software and associated documentation files (the "Software"), to deal in
7
+ # the Software without restriction, including without limitation the rights to
8
+ # use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9
+ # the Software, and to permit persons to whom the Software is furnished to do so,
10
+ # subject to the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be included in all
13
+ # copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17
+ # FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18
+ # COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19
+ # IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20
+ # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
+ #
22
+ require 'active_record/connection_adapters/abstract/connection_pool'
23
+
24
+ module AdvancedConnection
25
+ module ActiveRecordExt
26
+ module ConnectionPool
27
+ extend ActiveSupport::Autoload
28
+
29
+ eager_autoload do
30
+ autoload :Queues
31
+ autoload :IdleManager
32
+ autoload :StatementPooling
33
+ autoload :TransactionEncapsulation
34
+ autoload :WithoutConnection
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,30 @@
1
+ #
2
+ # Copyright (C) 2016 Finalsite, LLC
3
+ # Copyright (C) 2016 Carl P. Corliss <carl.corliss@finalsite.com>
4
+ #
5
+ # Permission is hereby granted, free of charge, to any person obtaining a copy of
6
+ # this software and associated documentation files (the "Software"), to deal in
7
+ # the Software without restriction, including without limitation the rights to
8
+ # use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9
+ # the Software, and to permit persons to whom the Software is furnished to do so,
10
+ # subject to the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be included in all
13
+ # copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17
+ # FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18
+ # COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19
+ # IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20
+ # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
+ #
22
+ module AdvancedConnection
23
+ module ActiveRecordExt
24
+ module WithoutConnection
25
+ def without_connection(&block)
26
+ connection_pool.without_connection(&block)
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,59 @@
1
+ #
2
+ # Copyright (C) 2016 Finalsite, LLC
3
+ # Copyright (C) 2016 Carl P. Corliss <carl.corliss@finalsite.com>
4
+ #
5
+ # Permission is hereby granted, free of charge, to any person obtaining a copy of
6
+ # this software and associated documentation files (the "Software"), to deal in
7
+ # the Software without restriction, including without limitation the rights to
8
+ # use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9
+ # the Software, and to permit persons to whom the Software is furnished to do so,
10
+ # subject to the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be included in all
13
+ # copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17
+ # FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18
+ # COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19
+ # IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20
+ # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
+ #
22
+ require 'active_record/connection_adapters/abstract_adapter'
23
+
24
+ module AdvancedConnection
25
+ module ActiveRecordExt
26
+ extend ActiveSupport::Concern
27
+ extend ActiveSupport::Autoload
28
+
29
+ eager_autoload do
30
+ autoload :AbstractAdapter
31
+ autoload :ConnectionPool
32
+ autoload :WithoutConnection
33
+ end
34
+
35
+ included do
36
+ ActiveRecord::ConnectionAdapters::AbstractAdapter.instance_exec do
37
+ include AbstractAdapter
38
+ end
39
+
40
+ ActiveRecord::ConnectionAdapters::ConnectionPool.instance_exec do
41
+ if AdvancedConnection.enable_idle_connection_manager
42
+ include ConnectionPool::IdleManager
43
+ end
44
+
45
+ if AdvancedConnection.enable_statement_pooling
46
+ include ConnectionPool::StatementPooling
47
+ elsif AdvancedConnection.enable_without_connection
48
+ include ConnectionPool::WithoutConnection
49
+ end
50
+ end
51
+
52
+ ActiveRecord::Base.instance_exec do
53
+ if AdvancedConnection.enable_without_connection
54
+ extend ActiveRecordExt::WithoutConnection unless AdvancedConnection::enable_statement_pooling
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,247 @@
1
+ #
2
+ # Copyright (C) 2016 Finalsite, LLC
3
+ # Copyright (C) 2016 Carl P. Corliss <carl.corliss@finalsite.com>
4
+ #
5
+ # Permission is hereby granted, free of charge, to any person obtaining a copy of
6
+ # this software and associated documentation files (the "Software"), to deal in
7
+ # the Software without restriction, including without limitation the rights to
8
+ # use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9
+ # the Software, and to permit persons to whom the Software is furnished to do so,
10
+ # subject to the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be included in all
13
+ # copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17
+ # FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18
+ # COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19
+ # IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20
+ # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
+ #
22
+ require 'singleton'
23
+
24
+ module AdvancedConnection
25
+ class Config
26
+ include Singleton
27
+
28
+ VALID_QUEUE_TYPES = [
29
+ :fifo, :lifo, :stack, :prefer_younger, :prefer_older
30
+ ].freeze unless defined? VALID_QUEUE_TYPES
31
+
32
+ CALLBACK_TYPES = ActiveSupport::OrderedOptions.new.merge({
33
+ before: nil,
34
+ around: nil,
35
+ after: nil
36
+ }).freeze unless defined? CALLBACK_TYPES
37
+
38
+ DEFAULT_CONFIG = ActiveSupport::OrderedOptions.new.merge({
39
+ :enable_without_connection => false,
40
+ :enable_statement_pooling => false,
41
+ :enable_idle_connection_manager => false,
42
+ :connection_pool_queue_type => :fifo,
43
+ :warmup_connections => false,
44
+ :min_idle_connections => 0,
45
+ :max_idle_connections => ::Float::INFINITY,
46
+ :max_idle_time => 0,
47
+ :idle_check_interval => 0,
48
+ :callbacks => ActiveSupport::OrderedOptions.new
49
+ }).freeze unless defined? DEFAULT_CONFIG
50
+
51
+ class << self
52
+ def method_missing(method, *args, &block)
53
+ return super unless instance.include?(method) || instance.respond_to?(method)
54
+ instance.public_send(method, *args, &block)
55
+ end
56
+
57
+ def respond_to_missing?(method, include_private = false)
58
+ instance.respond_to?(method) || super
59
+ end
60
+
61
+ def include?(key)
62
+ instance.include?(key) || super
63
+ end
64
+
65
+ def add_callback(*names)
66
+ Array(names).flatten.each { |name|
67
+ class_eval(<<-EOS, __FILE__, __LINE__ + 1)
68
+ def #{name}_callbacks
69
+ @config.callbacks.#{name} ||= CALLBACK_TYPES.dup
70
+ end
71
+
72
+ def #{name}_callbacks=(value)
73
+ if not value.is_a? Hash
74
+ fail Error::ConfigError, "#{name} callbacks must be a hash"
75
+ elsif (bad_options = (value.keys.collect(&:to_sym) - CALLBACK_TYPES.keys)).size > 0
76
+ plural = bad_options .size > 1 ? 's' : ''
77
+ fail Error::ConfigError, "Unexpected callback option\#{plural}: " \
78
+ " `\#{bad_options.join('`, `')}`"
79
+ elsif (uncallable = value.select { |k,v| !v.respond_to? :call }).present?
80
+ plural = uncallable.size > 1 ? 's' : ''
81
+ fail Error::ConfigError, "Expected #{name} callback\#{plural}" \
82
+ " `\#{uncallable.keys.join('`, `')}` to be callable"
83
+ end
84
+
85
+ @config.callbacks.#{name} = CALLBACK_TYPES.merge(value)
86
+ end
87
+ EOS
88
+ DEFAULT_CONFIG.callbacks[name.to_sym] = CALLBACK_TYPES.dup
89
+ }
90
+ end
91
+ alias_method :add_callbacks, :add_callback
92
+ end
93
+
94
+ add_callbacks :without_connection, :statement_pooling
95
+
96
+ def initialize
97
+ @loaded = false
98
+ @config = DEFAULT_CONFIG.deep_dup
99
+ end
100
+
101
+ def loaded!
102
+ @loaded = true
103
+ end
104
+
105
+ def loaded?
106
+ @loaded
107
+ end
108
+
109
+ def [](key)
110
+ @config[key.to_sym]
111
+ end
112
+
113
+ def []=(key, value)
114
+ public_send("#{key}=".to_sym, value)
115
+ end
116
+
117
+ def include?(key)
118
+ @config.include? key.to_s.tr('=', '').to_sym
119
+ end
120
+
121
+ def to_h
122
+ @config.dup
123
+ end
124
+
125
+ def callbacks
126
+ @config.callbacks
127
+ end
128
+
129
+ def enable_without_connection
130
+ @config[:enable_without_connection]
131
+ end
132
+
133
+ def enable_without_connection=(value)
134
+ if enable_statement_pooling && !!value
135
+ raise Error::ConfigError, "WithoutConnection blocks conflict with Statement Pooling feature"
136
+ end
137
+ @config[:enable_without_connection] = !!value
138
+ end
139
+
140
+ def enable_statement_pooling
141
+ @config[:enable_statement_pooling]
142
+ end
143
+
144
+ def enable_statement_pooling=(value)
145
+ if enable_without_connection && !!value
146
+ raise Error::ConfigError, "Statement Pooling conflicts with WithoutConnection feature"
147
+ end
148
+ @config[:enable_statement_pooling] = !!value
149
+ end
150
+
151
+ def enable_idle_connection_manager
152
+ @config[:enable_idle_connection_manager]
153
+ end
154
+
155
+ def enable_idle_connection_manager=(value)
156
+ @config[:enable_idle_connection_manager] = !!value
157
+ end
158
+
159
+ def warmup_connections
160
+ @config[:warmup_connections]
161
+ end
162
+
163
+ def warmup_connections=(value)
164
+ unless value.nil? || value === false || value.is_a?(Fixnum) || value =~ /^\d+$/
165
+ fail Error::ConfigError, 'Expected warmup_connections to be nil, false ' \
166
+ "or a valid positive integer, but found `#{value.inspect}`"
167
+ end
168
+
169
+ if value.to_s =~ /^\d+$/
170
+ @config[:warmup_connections] = value.to_i
171
+ else
172
+ @config[:warmup_connections] = false
173
+ end
174
+ end
175
+
176
+ def min_idle_connections
177
+ @config[:min_idle_connections]
178
+ end
179
+
180
+ def min_idle_connections=(value)
181
+ unless value.is_a?(Numeric) || value =~ /^\d+$/
182
+ fail Error::ConfigError, 'Expected min_idle_connections to be ' \
183
+ "a valid integer value, but found `#{value.inspect}`"
184
+ end
185
+ @config[:min_idle_connections] = value.to_i
186
+ end
187
+
188
+ def max_idle_connections
189
+ @config[:max_idle_connections]
190
+ end
191
+
192
+ def max_idle_connections=(value)
193
+ unless value.is_a?(Numeric) || value =~ /^\d+$/
194
+ fail Error::ConfigError, 'Expected max_idle_connections to be ' \
195
+ "a valid integer value, but found `#{value.inspect}`"
196
+ end
197
+ @config[:max_idle_connections] = begin
198
+ value.to_i
199
+ rescue FloatDomainError => e
200
+ raise unless e.message =~ /infinity/i
201
+ ::Float::INFINITY
202
+ end
203
+ end
204
+
205
+ def max_idle_time
206
+ @config[:max_idle_time]
207
+ end
208
+
209
+ def max_idle_time=(value)
210
+ unless value.is_a?(Numeric) || value =~ /^\d+$/
211
+ fail Error::ConfigError, 'Expected max_idle_time to be ' \
212
+ "a valid integer value, but found `#{value.inspect}`"
213
+ end
214
+ @config[:max_idle_time] = value.to_i
215
+ end
216
+
217
+ def idle_check_interval
218
+ @config[:idle_check_interval]
219
+ end
220
+
221
+ def idle_check_interval=(value)
222
+ unless value.is_a?(Numeric) || value =~ /^\d+$/
223
+ fail Error::ConfigError, 'Expected idle_check_interval to be ' \
224
+ "a valid integer value, but found `#{value.inspect}`"
225
+ end
226
+ @config[:idle_check_interval] = value.to_i
227
+ end
228
+
229
+ def connection_pool_queue_type
230
+ @config[:connection_pool_queue_type]
231
+ end
232
+
233
+ def connection_pool_queue_type=(value)
234
+ unless value.is_a?(String) || value.is_a?(Symbol)
235
+ fail Error::ConfigError, 'Expected String or Symbol for connection_pool_queue_type ' \
236
+ "but found `#{value.class.name}`"
237
+ end
238
+
239
+ unless VALID_QUEUE_TYPES.include? value.to_sym
240
+ fail Error::ConfigError, 'Expected connection_pool_queue_type to be one of ' \
241
+ ':fifo, :lifo, :stack, :prefer_younger, or :prefer_older ' \
242
+ "but found `#{value.inspect}`"
243
+ end
244
+ @config[:connection_pool_queue_type] = value
245
+ end
246
+ end
247
+ end