viking-sequel 3.10.0
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.
- data/CHANGELOG +3134 -0
- data/COPYING +19 -0
- data/README.rdoc +723 -0
- data/Rakefile +193 -0
- data/bin/sequel +196 -0
- data/doc/advanced_associations.rdoc +644 -0
- data/doc/cheat_sheet.rdoc +218 -0
- data/doc/dataset_basics.rdoc +106 -0
- data/doc/dataset_filtering.rdoc +158 -0
- data/doc/opening_databases.rdoc +296 -0
- data/doc/prepared_statements.rdoc +104 -0
- data/doc/reflection.rdoc +84 -0
- data/doc/release_notes/1.0.txt +38 -0
- data/doc/release_notes/1.1.txt +143 -0
- data/doc/release_notes/1.3.txt +101 -0
- data/doc/release_notes/1.4.0.txt +53 -0
- data/doc/release_notes/1.5.0.txt +155 -0
- data/doc/release_notes/2.0.0.txt +298 -0
- data/doc/release_notes/2.1.0.txt +271 -0
- data/doc/release_notes/2.10.0.txt +328 -0
- data/doc/release_notes/2.11.0.txt +215 -0
- data/doc/release_notes/2.12.0.txt +534 -0
- data/doc/release_notes/2.2.0.txt +253 -0
- data/doc/release_notes/2.3.0.txt +88 -0
- data/doc/release_notes/2.4.0.txt +106 -0
- data/doc/release_notes/2.5.0.txt +137 -0
- data/doc/release_notes/2.6.0.txt +157 -0
- data/doc/release_notes/2.7.0.txt +166 -0
- data/doc/release_notes/2.8.0.txt +171 -0
- data/doc/release_notes/2.9.0.txt +97 -0
- data/doc/release_notes/3.0.0.txt +221 -0
- data/doc/release_notes/3.1.0.txt +406 -0
- data/doc/release_notes/3.10.0.txt +286 -0
- data/doc/release_notes/3.2.0.txt +268 -0
- data/doc/release_notes/3.3.0.txt +192 -0
- data/doc/release_notes/3.4.0.txt +325 -0
- data/doc/release_notes/3.5.0.txt +510 -0
- data/doc/release_notes/3.6.0.txt +366 -0
- data/doc/release_notes/3.7.0.txt +179 -0
- data/doc/release_notes/3.8.0.txt +151 -0
- data/doc/release_notes/3.9.0.txt +233 -0
- data/doc/schema.rdoc +36 -0
- data/doc/sharding.rdoc +113 -0
- data/doc/virtual_rows.rdoc +205 -0
- data/lib/sequel.rb +1 -0
- data/lib/sequel/adapters/ado.rb +90 -0
- data/lib/sequel/adapters/ado/mssql.rb +30 -0
- data/lib/sequel/adapters/amalgalite.rb +176 -0
- data/lib/sequel/adapters/db2.rb +139 -0
- data/lib/sequel/adapters/dbi.rb +113 -0
- data/lib/sequel/adapters/do.rb +188 -0
- data/lib/sequel/adapters/do/mysql.rb +49 -0
- data/lib/sequel/adapters/do/postgres.rb +91 -0
- data/lib/sequel/adapters/do/sqlite.rb +40 -0
- data/lib/sequel/adapters/firebird.rb +283 -0
- data/lib/sequel/adapters/informix.rb +77 -0
- data/lib/sequel/adapters/jdbc.rb +587 -0
- data/lib/sequel/adapters/jdbc/as400.rb +58 -0
- data/lib/sequel/adapters/jdbc/h2.rb +133 -0
- data/lib/sequel/adapters/jdbc/mssql.rb +57 -0
- data/lib/sequel/adapters/jdbc/mysql.rb +78 -0
- data/lib/sequel/adapters/jdbc/oracle.rb +50 -0
- data/lib/sequel/adapters/jdbc/postgresql.rb +108 -0
- data/lib/sequel/adapters/jdbc/sqlite.rb +55 -0
- data/lib/sequel/adapters/mysql.rb +421 -0
- data/lib/sequel/adapters/odbc.rb +143 -0
- data/lib/sequel/adapters/odbc/mssql.rb +42 -0
- data/lib/sequel/adapters/openbase.rb +64 -0
- data/lib/sequel/adapters/oracle.rb +131 -0
- data/lib/sequel/adapters/postgres.rb +504 -0
- data/lib/sequel/adapters/shared/mssql.rb +490 -0
- data/lib/sequel/adapters/shared/mysql.rb +498 -0
- data/lib/sequel/adapters/shared/oracle.rb +195 -0
- data/lib/sequel/adapters/shared/postgres.rb +830 -0
- data/lib/sequel/adapters/shared/progress.rb +44 -0
- data/lib/sequel/adapters/shared/sqlite.rb +389 -0
- data/lib/sequel/adapters/sqlite.rb +224 -0
- data/lib/sequel/adapters/utils/stored_procedures.rb +84 -0
- data/lib/sequel/connection_pool.rb +99 -0
- data/lib/sequel/connection_pool/sharded_single.rb +84 -0
- data/lib/sequel/connection_pool/sharded_threaded.rb +211 -0
- data/lib/sequel/connection_pool/single.rb +29 -0
- data/lib/sequel/connection_pool/threaded.rb +150 -0
- data/lib/sequel/core.rb +293 -0
- data/lib/sequel/core_sql.rb +241 -0
- data/lib/sequel/database.rb +1079 -0
- data/lib/sequel/database/schema_generator.rb +327 -0
- data/lib/sequel/database/schema_methods.rb +203 -0
- data/lib/sequel/database/schema_sql.rb +320 -0
- data/lib/sequel/dataset.rb +32 -0
- data/lib/sequel/dataset/actions.rb +441 -0
- data/lib/sequel/dataset/features.rb +86 -0
- data/lib/sequel/dataset/graph.rb +254 -0
- data/lib/sequel/dataset/misc.rb +119 -0
- data/lib/sequel/dataset/mutation.rb +64 -0
- data/lib/sequel/dataset/prepared_statements.rb +227 -0
- data/lib/sequel/dataset/query.rb +709 -0
- data/lib/sequel/dataset/sql.rb +996 -0
- data/lib/sequel/exceptions.rb +51 -0
- data/lib/sequel/extensions/blank.rb +43 -0
- data/lib/sequel/extensions/inflector.rb +242 -0
- data/lib/sequel/extensions/looser_typecasting.rb +21 -0
- data/lib/sequel/extensions/migration.rb +239 -0
- data/lib/sequel/extensions/named_timezones.rb +61 -0
- data/lib/sequel/extensions/pagination.rb +100 -0
- data/lib/sequel/extensions/pretty_table.rb +82 -0
- data/lib/sequel/extensions/query.rb +52 -0
- data/lib/sequel/extensions/schema_dumper.rb +271 -0
- data/lib/sequel/extensions/sql_expr.rb +122 -0
- data/lib/sequel/extensions/string_date_time.rb +46 -0
- data/lib/sequel/extensions/thread_local_timezones.rb +48 -0
- data/lib/sequel/metaprogramming.rb +9 -0
- data/lib/sequel/model.rb +120 -0
- data/lib/sequel/model/associations.rb +1514 -0
- data/lib/sequel/model/base.rb +1069 -0
- data/lib/sequel/model/default_inflections.rb +45 -0
- data/lib/sequel/model/errors.rb +39 -0
- data/lib/sequel/model/exceptions.rb +21 -0
- data/lib/sequel/model/inflections.rb +162 -0
- data/lib/sequel/model/plugins.rb +70 -0
- data/lib/sequel/plugins/active_model.rb +59 -0
- data/lib/sequel/plugins/association_dependencies.rb +103 -0
- data/lib/sequel/plugins/association_proxies.rb +41 -0
- data/lib/sequel/plugins/boolean_readers.rb +53 -0
- data/lib/sequel/plugins/caching.rb +141 -0
- data/lib/sequel/plugins/class_table_inheritance.rb +214 -0
- data/lib/sequel/plugins/composition.rb +138 -0
- data/lib/sequel/plugins/force_encoding.rb +72 -0
- data/lib/sequel/plugins/hook_class_methods.rb +126 -0
- data/lib/sequel/plugins/identity_map.rb +116 -0
- data/lib/sequel/plugins/instance_filters.rb +98 -0
- data/lib/sequel/plugins/instance_hooks.rb +57 -0
- data/lib/sequel/plugins/lazy_attributes.rb +77 -0
- data/lib/sequel/plugins/many_through_many.rb +208 -0
- data/lib/sequel/plugins/nested_attributes.rb +206 -0
- data/lib/sequel/plugins/optimistic_locking.rb +81 -0
- data/lib/sequel/plugins/rcte_tree.rb +281 -0
- data/lib/sequel/plugins/schema.rb +66 -0
- data/lib/sequel/plugins/serialization.rb +166 -0
- data/lib/sequel/plugins/single_table_inheritance.rb +74 -0
- data/lib/sequel/plugins/subclasses.rb +45 -0
- data/lib/sequel/plugins/tactical_eager_loading.rb +61 -0
- data/lib/sequel/plugins/timestamps.rb +87 -0
- data/lib/sequel/plugins/touch.rb +118 -0
- data/lib/sequel/plugins/typecast_on_load.rb +72 -0
- data/lib/sequel/plugins/validation_class_methods.rb +405 -0
- data/lib/sequel/plugins/validation_helpers.rb +223 -0
- data/lib/sequel/sql.rb +1020 -0
- data/lib/sequel/timezones.rb +161 -0
- data/lib/sequel/version.rb +12 -0
- data/lib/sequel_core.rb +1 -0
- data/lib/sequel_model.rb +1 -0
- data/spec/adapters/firebird_spec.rb +407 -0
- data/spec/adapters/informix_spec.rb +97 -0
- data/spec/adapters/mssql_spec.rb +403 -0
- data/spec/adapters/mysql_spec.rb +1019 -0
- data/spec/adapters/oracle_spec.rb +286 -0
- data/spec/adapters/postgres_spec.rb +969 -0
- data/spec/adapters/spec_helper.rb +51 -0
- data/spec/adapters/sqlite_spec.rb +432 -0
- data/spec/core/connection_pool_spec.rb +808 -0
- data/spec/core/core_sql_spec.rb +417 -0
- data/spec/core/database_spec.rb +1662 -0
- data/spec/core/dataset_spec.rb +3827 -0
- data/spec/core/expression_filters_spec.rb +595 -0
- data/spec/core/object_graph_spec.rb +296 -0
- data/spec/core/schema_generator_spec.rb +159 -0
- data/spec/core/schema_spec.rb +830 -0
- data/spec/core/spec_helper.rb +56 -0
- data/spec/core/version_spec.rb +7 -0
- data/spec/extensions/active_model_spec.rb +76 -0
- data/spec/extensions/association_dependencies_spec.rb +127 -0
- data/spec/extensions/association_proxies_spec.rb +50 -0
- data/spec/extensions/blank_spec.rb +67 -0
- data/spec/extensions/boolean_readers_spec.rb +92 -0
- data/spec/extensions/caching_spec.rb +250 -0
- data/spec/extensions/class_table_inheritance_spec.rb +252 -0
- data/spec/extensions/composition_spec.rb +194 -0
- data/spec/extensions/force_encoding_spec.rb +117 -0
- data/spec/extensions/hook_class_methods_spec.rb +470 -0
- data/spec/extensions/identity_map_spec.rb +202 -0
- data/spec/extensions/inflector_spec.rb +181 -0
- data/spec/extensions/instance_filters_spec.rb +55 -0
- data/spec/extensions/instance_hooks_spec.rb +133 -0
- data/spec/extensions/lazy_attributes_spec.rb +153 -0
- data/spec/extensions/looser_typecasting_spec.rb +39 -0
- data/spec/extensions/many_through_many_spec.rb +884 -0
- data/spec/extensions/migration_spec.rb +332 -0
- data/spec/extensions/named_timezones_spec.rb +72 -0
- data/spec/extensions/nested_attributes_spec.rb +396 -0
- data/spec/extensions/optimistic_locking_spec.rb +100 -0
- data/spec/extensions/pagination_spec.rb +99 -0
- data/spec/extensions/pretty_table_spec.rb +91 -0
- data/spec/extensions/query_spec.rb +85 -0
- data/spec/extensions/rcte_tree_spec.rb +205 -0
- data/spec/extensions/schema_dumper_spec.rb +357 -0
- data/spec/extensions/schema_spec.rb +127 -0
- data/spec/extensions/serialization_spec.rb +209 -0
- data/spec/extensions/single_table_inheritance_spec.rb +96 -0
- data/spec/extensions/spec_helper.rb +91 -0
- data/spec/extensions/sql_expr_spec.rb +89 -0
- data/spec/extensions/string_date_time_spec.rb +93 -0
- data/spec/extensions/subclasses_spec.rb +52 -0
- data/spec/extensions/tactical_eager_loading_spec.rb +65 -0
- data/spec/extensions/thread_local_timezones_spec.rb +45 -0
- data/spec/extensions/timestamps_spec.rb +150 -0
- data/spec/extensions/touch_spec.rb +155 -0
- data/spec/extensions/typecast_on_load_spec.rb +69 -0
- data/spec/extensions/validation_class_methods_spec.rb +984 -0
- data/spec/extensions/validation_helpers_spec.rb +438 -0
- data/spec/integration/associations_test.rb +281 -0
- data/spec/integration/database_test.rb +26 -0
- data/spec/integration/dataset_test.rb +963 -0
- data/spec/integration/eager_loader_test.rb +734 -0
- data/spec/integration/model_test.rb +130 -0
- data/spec/integration/plugin_test.rb +814 -0
- data/spec/integration/prepared_statement_test.rb +213 -0
- data/spec/integration/schema_test.rb +361 -0
- data/spec/integration/spec_helper.rb +73 -0
- data/spec/integration/timezone_test.rb +55 -0
- data/spec/integration/transaction_test.rb +122 -0
- data/spec/integration/type_test.rb +96 -0
- data/spec/model/association_reflection_spec.rb +175 -0
- data/spec/model/associations_spec.rb +2633 -0
- data/spec/model/base_spec.rb +418 -0
- data/spec/model/dataset_methods_spec.rb +78 -0
- data/spec/model/eager_loading_spec.rb +1391 -0
- data/spec/model/hooks_spec.rb +240 -0
- data/spec/model/inflector_spec.rb +26 -0
- data/spec/model/model_spec.rb +593 -0
- data/spec/model/plugins_spec.rb +236 -0
- data/spec/model/record_spec.rb +1500 -0
- data/spec/model/spec_helper.rb +97 -0
- data/spec/model/validations_spec.rb +153 -0
- data/spec/rcov.opts +6 -0
- data/spec/spec_config.rb.example +10 -0
- metadata +346 -0
@@ -0,0 +1,84 @@
|
|
1
|
+
module Sequel
|
2
|
+
class Dataset
|
3
|
+
module StoredProcedureMethods
|
4
|
+
SQL_QUERY_TYPE = Hash.new{|h,k| h[k] = k}
|
5
|
+
SQL_QUERY_TYPE[:first] = SQL_QUERY_TYPE[:all] = :select
|
6
|
+
|
7
|
+
# The name of the stored procedure to call
|
8
|
+
attr_accessor :sproc_name
|
9
|
+
|
10
|
+
# The name of the stored procedure to call
|
11
|
+
attr_writer :sproc_args
|
12
|
+
|
13
|
+
# Call the stored procedure with the given args
|
14
|
+
def call(*args, &block)
|
15
|
+
sp = clone
|
16
|
+
sp.sproc_args = args
|
17
|
+
sp.run(&block)
|
18
|
+
end
|
19
|
+
|
20
|
+
# Programmer friendly string showing this is a stored procedure,
|
21
|
+
# showing the name of the procedure.
|
22
|
+
def inspect
|
23
|
+
"<#{self.class.name}/StoredProcedure name=#{@sproc_name}>"
|
24
|
+
end
|
25
|
+
|
26
|
+
# Run the stored procedure with the current args on the database
|
27
|
+
def run(&block)
|
28
|
+
case @sproc_type
|
29
|
+
when :select, :all
|
30
|
+
all(&block)
|
31
|
+
when :first
|
32
|
+
first
|
33
|
+
when :insert
|
34
|
+
insert
|
35
|
+
when :update
|
36
|
+
update
|
37
|
+
when :delete
|
38
|
+
delete
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
# Set the type of the stored procedure and override the corresponding _sql
|
43
|
+
# method to return the empty string (since the result will be
|
44
|
+
# ignored anyway).
|
45
|
+
def sproc_type=(type)
|
46
|
+
@sproc_type = type
|
47
|
+
meta_def("#{sql_query_type}_sql"){|*a| ''}
|
48
|
+
end
|
49
|
+
|
50
|
+
private
|
51
|
+
|
52
|
+
# The type of query (:select, :insert, :delete, :update).
|
53
|
+
def sql_query_type
|
54
|
+
SQL_QUERY_TYPE[@sproc_type]
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
module StoredProcedures
|
59
|
+
# For the given type (:select, :first, :insert, :update, or :delete),
|
60
|
+
# run the database stored procedure with the given name with the given
|
61
|
+
# arguments.
|
62
|
+
def call_sproc(type, name, *args)
|
63
|
+
prepare_sproc(type, name).call(*args)
|
64
|
+
end
|
65
|
+
|
66
|
+
# Transform this dataset into a stored procedure that you can call
|
67
|
+
# multiple times with new arguments.
|
68
|
+
def prepare_sproc(type, name)
|
69
|
+
sp = clone
|
70
|
+
prepare_extend_sproc(sp)
|
71
|
+
sp.sproc_type = type
|
72
|
+
sp.sproc_name = name
|
73
|
+
sp
|
74
|
+
end
|
75
|
+
|
76
|
+
private
|
77
|
+
|
78
|
+
# Extend the dataset with the stored procedure methods.
|
79
|
+
def prepare_extend_sproc(ds)
|
80
|
+
ds.extend(StoredProcedureMethods)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
@@ -0,0 +1,99 @@
|
|
1
|
+
# The base connection pool class, which all other connection pools are built
|
2
|
+
# on. This class is not instantiated directly, but subclasses should at
|
3
|
+
# the very least implement the following API:
|
4
|
+
# * initialize(Hash, &block) - The block is used as the connection proc,
|
5
|
+
# which should accept a single symbol argument.
|
6
|
+
# * hold(Symbol, &block) - yield a connection object (obtained from calling
|
7
|
+
# the block passed to initialize) to the current block. For sharded
|
8
|
+
# connection pools, the Symbol passed is the shard/server to use.
|
9
|
+
# * disconnect(Symbol, &block) - disconnect the connection object. If a
|
10
|
+
# block is given, pass the connection option to it, otherwise use the
|
11
|
+
# :disconnection_proc option in the hash passed to initialize. For sharded
|
12
|
+
# connection pools, the Symbol passed is the shard/server to use.
|
13
|
+
# * servers - an array of shard/server symbols for all shards/servers that this
|
14
|
+
# connection pool recognizes.
|
15
|
+
# * size - an integer representing the total number of connections in the pool,
|
16
|
+
# or for the given shard/server if sharding is supported.
|
17
|
+
#
|
18
|
+
# For sharded connection pools, the sharded API:
|
19
|
+
# * add_servers(Array of Symbols) - start recognizing all shards/servers specified
|
20
|
+
# by the array of symbols.
|
21
|
+
# * remove_servers(Array of Symbols) - no longer recognize all shards/servers
|
22
|
+
# specified by the array of symbols.
|
23
|
+
class Sequel::ConnectionPool
|
24
|
+
# The default server to use
|
25
|
+
DEFAULT_SERVER = :default
|
26
|
+
|
27
|
+
# A map of [single threaded, sharded] values to files (indicating strings to
|
28
|
+
# be required) ConnectionPool subclasses.
|
29
|
+
CONNECTION_POOL_MAP = {[true, false] => :single,
|
30
|
+
[true, true] => :sharded_single,
|
31
|
+
[false, false] => :threaded,
|
32
|
+
[false, true] => :sharded_threaded}
|
33
|
+
|
34
|
+
# Class methods used to return an appropriate pool subclass, separated
|
35
|
+
# into a module for easier overridding by extensions.
|
36
|
+
module ClassMethods
|
37
|
+
# Return a pool subclass instance based on the given options. If a :pool_class
|
38
|
+
# option is provided is provided, use that pool class, otherwise
|
39
|
+
# use a new instance of an appropriate pool subclass based on the
|
40
|
+
# :single_threaded and :servers options.
|
41
|
+
def get_pool(opts = {}, &block)
|
42
|
+
case v = connection_pool_class(opts)
|
43
|
+
when Class
|
44
|
+
v.new(opts, &block)
|
45
|
+
when Symbol
|
46
|
+
Sequel.ts_require("connection_pool/#{v}")
|
47
|
+
connection_pool_class(opts).new(opts, &block) || raise(Sequel::Error, "No connection pool class found")
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
private
|
52
|
+
|
53
|
+
# Return a connection pool class based on the given options.
|
54
|
+
def connection_pool_class(opts)
|
55
|
+
opts[:pool_class] || CONNECTION_POOL_MAP[[!!opts[:single_threaded], !!opts[:servers]]]
|
56
|
+
end
|
57
|
+
end
|
58
|
+
extend ClassMethods
|
59
|
+
|
60
|
+
# Instantiates a connection pool with the given options. The block is called
|
61
|
+
# with a single symbol (specifying the server/shard to use) every time a new
|
62
|
+
# connection is needed. The following options are respected for all connection
|
63
|
+
# pools:
|
64
|
+
# * :after_connect - The proc called after each new connection is made, with the
|
65
|
+
# connection object, useful for customizations that you want to apply to all
|
66
|
+
# connections.
|
67
|
+
# * :disconnection_proc - The proc called when removing connections from the pool,
|
68
|
+
# which is passed the connection to disconnect.
|
69
|
+
def initialize(opts={}, &block)
|
70
|
+
raise(Sequel::Error, "No connection proc specified") unless @connection_proc = block
|
71
|
+
@disconnection_proc = opts[:disconnection_proc]
|
72
|
+
@after_connect = opts[:after_connect]
|
73
|
+
end
|
74
|
+
|
75
|
+
# Alias for size, not aliased directly for ease of subclass implementation
|
76
|
+
def created_count(*args)
|
77
|
+
size(*args)
|
78
|
+
end
|
79
|
+
|
80
|
+
# An array of symbols for all shards/servers, which is a single :default by default.
|
81
|
+
def servers
|
82
|
+
[:default]
|
83
|
+
end
|
84
|
+
|
85
|
+
private
|
86
|
+
|
87
|
+
# Return a new connection by calling the connection proc with the given server name,
|
88
|
+
# and checking for connection errors.
|
89
|
+
def make_new(server)
|
90
|
+
begin
|
91
|
+
conn = @connection_proc.call(server)
|
92
|
+
@after_connect.call(conn) if @after_connect
|
93
|
+
rescue Exception=>exception
|
94
|
+
raise Sequel.convert_exception_class(exception, Sequel::DatabaseConnectionError)
|
95
|
+
end
|
96
|
+
raise(Sequel::DatabaseConnectionError, "Connection parameters not valid") unless conn
|
97
|
+
conn
|
98
|
+
end
|
99
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
# A ShardedSingleConnectionPool is a single threaded connection pool that
|
2
|
+
# works with multiple shards/servers.
|
3
|
+
class Sequel::ShardedSingleConnectionPool < Sequel::ConnectionPool
|
4
|
+
# Initializes the instance with the supplied block as the connection_proc.
|
5
|
+
#
|
6
|
+
# The single threaded pool takes the following options:
|
7
|
+
#
|
8
|
+
# * :servers - A hash of servers to use. Keys should be symbols. If not
|
9
|
+
# present, will use a single :default server. The server name symbol will
|
10
|
+
# be passed to the connection_proc.
|
11
|
+
def initialize(opts={}, &block)
|
12
|
+
super
|
13
|
+
@conns = {}
|
14
|
+
@servers = Hash.new(:default)
|
15
|
+
add_servers([:default])
|
16
|
+
add_servers(opts[:servers].keys) if opts[:servers]
|
17
|
+
end
|
18
|
+
|
19
|
+
# Adds new servers to the connection pool. Primarily used in conjunction with master/slave
|
20
|
+
# or shard configurations. Allows for dynamic expansion of the potential slaves/shards
|
21
|
+
# at runtime. servers argument should be an array of symbols.
|
22
|
+
def add_servers(servers)
|
23
|
+
servers.each{|s| @servers[s] = s}
|
24
|
+
end
|
25
|
+
|
26
|
+
# The connection for the given server.
|
27
|
+
def conn(server=:default)
|
28
|
+
@conns[@servers[server]]
|
29
|
+
end
|
30
|
+
|
31
|
+
# Disconnects from the database. Once a connection is requested using
|
32
|
+
# #hold, the connection is reestablished. Options:
|
33
|
+
# * :server - Should be a symbol specifing the server to disconnect from,
|
34
|
+
# or an array of symbols to specify multiple servers.
|
35
|
+
def disconnect(opts={}, &block)
|
36
|
+
block ||= @disconnection_proc
|
37
|
+
(opts[:server] ? Array(opts[:server]) : servers).each{|s| disconnect_server(s, &block)}
|
38
|
+
end
|
39
|
+
|
40
|
+
# Yields the connection to the supplied block for the given server.
|
41
|
+
# This method simulates the ConnectionPool#hold API.
|
42
|
+
def hold(server=:default)
|
43
|
+
begin
|
44
|
+
server = @servers[server]
|
45
|
+
yield(@conns[server] ||= make_new(server))
|
46
|
+
rescue Sequel::DatabaseDisconnectError
|
47
|
+
disconnect_server(server, &@disconnection_proc)
|
48
|
+
raise
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
# Remove servers from the connection pool. Primarily used in conjunction with master/slave
|
53
|
+
# or shard configurations. Similar to disconnecting from all given servers,
|
54
|
+
# except that after it is used, future requests for the server will use the
|
55
|
+
# :default server instead.
|
56
|
+
def remove_servers(servers)
|
57
|
+
raise(Sequel::Error, "cannot remove default server") if servers.include?(:default)
|
58
|
+
servers.each do |server|
|
59
|
+
disconnect_server(server, &@disconnection_proc)
|
60
|
+
@servers.delete(server)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
# Return an array of symbols for servers in the connection pool.
|
65
|
+
def servers
|
66
|
+
@servers.keys
|
67
|
+
end
|
68
|
+
|
69
|
+
# The number of different shards/servers this pool is connected to.
|
70
|
+
def size
|
71
|
+
@conns.length
|
72
|
+
end
|
73
|
+
|
74
|
+
private
|
75
|
+
|
76
|
+
# Disconnect from the given server, if connected.
|
77
|
+
def disconnect_server(server, &block)
|
78
|
+
if conn = @conns.delete(server)
|
79
|
+
block.call(conn) if block
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
CONNECTION_POOL_MAP[[true, true]] = self
|
84
|
+
end
|
@@ -0,0 +1,211 @@
|
|
1
|
+
Sequel.require 'connection_pool/threaded'
|
2
|
+
|
3
|
+
# The slowest and most advanced connection, dealing with both multi-threaded
|
4
|
+
# access and configurations with multiple shards/servers.
|
5
|
+
#
|
6
|
+
# In addition, this pool subclass also handles scheduling in-use connections
|
7
|
+
# to be removed from the pool when they are returned to it.
|
8
|
+
class Sequel::ShardedThreadedConnectionPool < Sequel::ThreadedConnectionPool
|
9
|
+
# The following additional options are respected:
|
10
|
+
# * :servers - A hash of servers to use. Keys should be symbols. If not
|
11
|
+
# present, will use a single :default server. The server name symbol will
|
12
|
+
# be passed to the connection_proc.
|
13
|
+
def initialize(opts = {}, &block)
|
14
|
+
super
|
15
|
+
@available_connections = {}
|
16
|
+
@connections_to_remove = []
|
17
|
+
@servers = Hash.new(:default)
|
18
|
+
add_servers([:default])
|
19
|
+
add_servers(opts[:servers].keys) if opts[:servers]
|
20
|
+
end
|
21
|
+
|
22
|
+
# Adds new servers to the connection pool. Primarily used in conjunction with master/slave
|
23
|
+
# or shard configurations. Allows for dynamic expansion of the potential slaves/shards
|
24
|
+
# at runtime. servers argument should be an array of symbols.
|
25
|
+
def add_servers(servers)
|
26
|
+
sync do
|
27
|
+
servers.each do |server|
|
28
|
+
unless @servers.has_key?(server)
|
29
|
+
@servers[server] = server
|
30
|
+
@available_connections[server] = []
|
31
|
+
@allocated[server] = {}
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
# A hash of connections currently being used for the given server, key is the
|
38
|
+
# Thread, value is the connection. Nonexistent servers will return nil. Treat
|
39
|
+
# this as read only, do not modify the resulting object.
|
40
|
+
def allocated(server=:default)
|
41
|
+
@allocated[server]
|
42
|
+
end
|
43
|
+
|
44
|
+
# An array of connections opened but not currently used, for the given
|
45
|
+
# server. Nonexistent servers will return nil. Treat this as read only, do
|
46
|
+
# not modify the resulting object.
|
47
|
+
def available_connections(server=:default)
|
48
|
+
@available_connections[server]
|
49
|
+
end
|
50
|
+
|
51
|
+
# The total number of connections opened for the given server, should
|
52
|
+
# be equal to available_connections.length + allocated.length. Nonexistent
|
53
|
+
# servers will return the created count of the default server.
|
54
|
+
def size(server=:default)
|
55
|
+
server = @servers[server]
|
56
|
+
@allocated[server].length + @available_connections[server].length
|
57
|
+
end
|
58
|
+
|
59
|
+
# Removes all connection currently available on all servers, optionally
|
60
|
+
# yielding each connection to the given block. This method has the effect of
|
61
|
+
# disconnecting from the database, assuming that no connections are currently
|
62
|
+
# being used. If connections are being used, they are scheduled to be
|
63
|
+
# disconnected as soon as they are returned to the pool.
|
64
|
+
#
|
65
|
+
# Once a connection is requested using #hold, the connection pool
|
66
|
+
# creates new connections to the database. Options:
|
67
|
+
# * :server - Should be a symbol specifing the server to disconnect from,
|
68
|
+
# or an array of symbols to specify multiple servers.
|
69
|
+
def disconnect(opts={}, &block)
|
70
|
+
block ||= @disconnection_proc
|
71
|
+
sync do
|
72
|
+
(opts[:server] ? Array(opts[:server]) : @servers.keys).each do |s|
|
73
|
+
disconnect_server(s, &block)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
# Chooses the first available connection to the given server, or if none are
|
79
|
+
# available, creates a new connection. Passes the connection to the supplied
|
80
|
+
# block:
|
81
|
+
#
|
82
|
+
# pool.hold {|conn| conn.execute('DROP TABLE posts')}
|
83
|
+
#
|
84
|
+
# Pool#hold is re-entrant, meaning it can be called recursively in
|
85
|
+
# the same thread without blocking.
|
86
|
+
#
|
87
|
+
# If no connection is immediately available and the pool is already using the maximum
|
88
|
+
# number of connections, Pool#hold will block until a connection
|
89
|
+
# is available or the timeout expires. If the timeout expires before a
|
90
|
+
# connection can be acquired, a Sequel::PoolTimeout is
|
91
|
+
# raised.
|
92
|
+
def hold(server=:default)
|
93
|
+
sync{server = @servers[server]}
|
94
|
+
t = Thread.current
|
95
|
+
if conn = owned_connection(t, server)
|
96
|
+
return yield(conn)
|
97
|
+
end
|
98
|
+
begin
|
99
|
+
unless conn = acquire(t, server)
|
100
|
+
time = Time.now
|
101
|
+
timeout = time + @timeout
|
102
|
+
sleep_time = @sleep_time
|
103
|
+
sleep sleep_time
|
104
|
+
until conn = acquire(t, server)
|
105
|
+
raise(::Sequel::PoolTimeout) if Time.now > timeout
|
106
|
+
sleep sleep_time
|
107
|
+
end
|
108
|
+
end
|
109
|
+
yield conn
|
110
|
+
rescue Sequel::DatabaseDisconnectError
|
111
|
+
sync{@connections_to_remove << conn} if conn
|
112
|
+
raise
|
113
|
+
ensure
|
114
|
+
sync{release(t, conn, server)} if conn
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
# Remove servers from the connection pool. Primarily used in conjunction with master/slave
|
119
|
+
# or shard configurations. Similar to disconnecting from all given servers,
|
120
|
+
# except that after it is used, future requests for the server will use the
|
121
|
+
# :default server instead.
|
122
|
+
def remove_servers(servers)
|
123
|
+
sync do
|
124
|
+
raise(Sequel::Error, "cannot remove default server") if servers.include?(:default)
|
125
|
+
servers.each do |server|
|
126
|
+
if @servers.include?(server)
|
127
|
+
disconnect_server(server, &@disconnection_proc)
|
128
|
+
@available_connections.delete(server)
|
129
|
+
@allocated.delete(server)
|
130
|
+
@servers.delete(server)
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
# Return an array of symbols for servers in the connection pool.
|
137
|
+
def servers
|
138
|
+
sync{@servers.keys}
|
139
|
+
end
|
140
|
+
|
141
|
+
private
|
142
|
+
|
143
|
+
# Assigns a connection to the supplied thread for the given server, if one
|
144
|
+
# is available. The calling code should NOT already have the mutex when
|
145
|
+
# calling this.
|
146
|
+
def acquire(thread, server)
|
147
|
+
sync do
|
148
|
+
if conn = available(server)
|
149
|
+
allocated(server)[thread] = conn
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
# Returns an available connection to the given server. If no connection is
|
155
|
+
# available, tries to create a new connection. The calling code should already
|
156
|
+
# have the mutex before calling this.
|
157
|
+
def available(server)
|
158
|
+
available_connections(server).pop || make_new(server)
|
159
|
+
end
|
160
|
+
|
161
|
+
# Disconnect from the given server. Disconnects available connections
|
162
|
+
# immediately, and schedules currently allocated connections for disconnection
|
163
|
+
# as soon as they are returned to the pool. The calling code should already
|
164
|
+
# have the mutex before calling this.
|
165
|
+
def disconnect_server(server, &block)
|
166
|
+
if conns = available_connections(server)
|
167
|
+
conns.each{|conn| block.call(conn)} if block
|
168
|
+
conns.clear
|
169
|
+
end
|
170
|
+
@connections_to_remove.concat(allocated(server).values)
|
171
|
+
end
|
172
|
+
|
173
|
+
# Creates a new connection to the given server if the size of the pool for
|
174
|
+
# the server is less than the maximum size of the pool. The calling code
|
175
|
+
# should already have the mutex before calling this.
|
176
|
+
def make_new(server)
|
177
|
+
if (n = size(server)) >= @max_size
|
178
|
+
allocated(server).to_a.each{|t, c| release(t, c, server) unless t.alive?}
|
179
|
+
n = nil
|
180
|
+
end
|
181
|
+
default_make_new(server) if (n || size(server)) < @max_size
|
182
|
+
end
|
183
|
+
|
184
|
+
# Returns the connection owned by the supplied thread for the given server,
|
185
|
+
# if any. The calling code should NOT already have the mutex before calling this.
|
186
|
+
def owned_connection(thread, server)
|
187
|
+
sync{@allocated[server][thread]}
|
188
|
+
end
|
189
|
+
|
190
|
+
# Releases the connection assigned to the supplied thread and server. If the
|
191
|
+
# server or connection given is scheduled for disconnection, remove the
|
192
|
+
# connection instead of releasing it back to the pool.
|
193
|
+
# The calling code should already have the mutex before calling this.
|
194
|
+
def release(thread, conn, server)
|
195
|
+
if @connections_to_remove.include?(conn)
|
196
|
+
remove(thread, conn, server)
|
197
|
+
else
|
198
|
+
available_connections(server) << allocated(server).delete(thread)
|
199
|
+
end
|
200
|
+
end
|
201
|
+
|
202
|
+
# Removes the currently allocated connection from the connection pool. The
|
203
|
+
# calling code should already have the mutex before calling this.
|
204
|
+
def remove(thread, conn, server)
|
205
|
+
@connections_to_remove.delete(conn)
|
206
|
+
allocated(server).delete(thread) if @servers.include?(server)
|
207
|
+
@disconnection_proc.call(conn) if @disconnection_proc
|
208
|
+
end
|
209
|
+
|
210
|
+
CONNECTION_POOL_MAP[[false, true]] = self
|
211
|
+
end
|