advanced_connection 0.5.1

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