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.
- checksums.yaml +7 -0
- data/.document +5 -0
- data/.gitignore +8 -0
- data/.rspec +2 -0
- data/.travis.yml +63 -0
- data/Gemfile +3 -0
- data/Gemfile.lock +218 -0
- data/MIT-LICENSE +20 -0
- data/README.rdoc +3 -0
- data/Rakefile +165 -0
- data/advanced_connection.gemspec +49 -0
- data/gemfiles/jruby/rails4_1.gemfile +7 -0
- data/gemfiles/jruby/rails4_2.gemfile +7 -0
- data/gemfiles/ruby/rails4_1.gemfile +7 -0
- data/gemfiles/ruby/rails4_2.gemfile +7 -0
- data/lib/advanced_connection/active_record_ext/abstract_adapter/statement_pooling.rb +121 -0
- data/lib/advanced_connection/active_record_ext/abstract_adapter.rb +48 -0
- data/lib/advanced_connection/active_record_ext/connection_pool/idle_manager.rb +271 -0
- data/lib/advanced_connection/active_record_ext/connection_pool/queues.rb +60 -0
- data/lib/advanced_connection/active_record_ext/connection_pool/statement_pooling.rb +42 -0
- data/lib/advanced_connection/active_record_ext/connection_pool/without_connection.rb +93 -0
- data/lib/advanced_connection/active_record_ext/connection_pool.rb +38 -0
- data/lib/advanced_connection/active_record_ext/without_connection.rb +30 -0
- data/lib/advanced_connection/active_record_ext.rb +59 -0
- data/lib/advanced_connection/config.rb +247 -0
- data/lib/advanced_connection/error.rb +27 -0
- data/lib/advanced_connection/railtie.rb +40 -0
- data/lib/advanced_connection/version.rb +29 -0
- data/lib/advanced_connection.rb +65 -0
- data/lib/generators/advanced_connection/install/USAGE +5 -0
- data/lib/generators/advanced_connection/install/install_generator.rb +30 -0
- data/lib/generators/advanced_connection/install/templates/advanced_connection.rb +142 -0
- data/lib/tasks/advanced_connection_tasks.rake +25 -0
- data/spec/config/database.yml +18 -0
- data/spec/config/database.yml.erb +54 -0
- data/spec/dummy/.gitignore +1 -0
- data/spec/dummy/README.rdoc +28 -0
- data/spec/dummy/Rakefile +6 -0
- data/spec/dummy/app/assets/images/.keep +0 -0
- data/spec/dummy/app/assets/javascripts/application.js +13 -0
- data/spec/dummy/app/assets/stylesheets/application.css +15 -0
- data/spec/dummy/app/controllers/application_controller.rb +5 -0
- data/spec/dummy/app/controllers/concerns/.keep +0 -0
- data/spec/dummy/app/helpers/application_helper.rb +2 -0
- data/spec/dummy/app/mailers/.keep +0 -0
- data/spec/dummy/app/models/.keep +0 -0
- data/spec/dummy/app/models/book.rb +2 -0
- data/spec/dummy/app/models/concerns/.keep +0 -0
- data/spec/dummy/app/views/layouts/application.html.erb +13 -0
- data/spec/dummy/bin/bundle +3 -0
- data/spec/dummy/bin/rails +4 -0
- data/spec/dummy/bin/rake +4 -0
- data/spec/dummy/bin/setup +29 -0
- data/spec/dummy/config/application.rb +32 -0
- data/spec/dummy/config/boot.rb +5 -0
- data/spec/dummy/config/database.yml +17 -0
- data/spec/dummy/config/environment.rb +5 -0
- data/spec/dummy/config/environments/development.rb +48 -0
- data/spec/dummy/config/environments/production.rb +79 -0
- data/spec/dummy/config/environments/test.rb +42 -0
- data/spec/dummy/config/initializers/advanced_connection.rb +142 -0
- data/spec/dummy/config/initializers/assets.rb +11 -0
- data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/dummy/config/initializers/cookies_serializer.rb +3 -0
- data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -0
- data/spec/dummy/config/initializers/inflections.rb +16 -0
- data/spec/dummy/config/initializers/mime_types.rb +4 -0
- data/spec/dummy/config/initializers/session_store.rb +3 -0
- data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/spec/dummy/config/locales/en.yml +23 -0
- data/spec/dummy/config/routes.rb +56 -0
- data/spec/dummy/config/secrets.yml +22 -0
- data/spec/dummy/config.ru +4 -0
- data/spec/dummy/db/migrate/20160222045238_create_books.rb +10 -0
- data/spec/dummy/db/schema.rb +23 -0
- data/spec/dummy/lib/assets/.keep +0 -0
- data/spec/dummy/log/.keep +0 -0
- data/spec/dummy/log/test.log +327 -0
- data/spec/dummy/public/404.html +67 -0
- data/spec/dummy/public/422.html +67 -0
- data/spec/dummy/public/500.html +66 -0
- data/spec/dummy/public/favicon.ico +0 -0
- data/spec/dummy/test/fixtures/books.yml +9 -0
- data/spec/dummy/test/models/book_test.rb +7 -0
- data/spec/idle_manager_spec.rb +16 -0
- data/spec/spec_helper.rb +25 -0
- data/spec/support/db_config.rb +61 -0
- 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
|