active_record_shards 3.17.0 → 4.0.0.beta1
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 +5 -5
- data/README.md +50 -115
- data/lib/active_record_shards.rb +2 -14
- data/lib/active_record_shards/association_collection_connection_selection.rb +1 -2
- data/lib/active_record_shards/configuration_parser.rb +1 -2
- data/lib/active_record_shards/connection_switcher-5-0.rb +0 -10
- data/lib/active_record_shards/connection_switcher-5-1.rb +0 -10
- data/lib/active_record_shards/connection_switcher.rb +37 -51
- data/lib/active_record_shards/default_slave_patches.rb +36 -44
- data/lib/active_record_shards/model.rb +5 -20
- data/lib/active_record_shards/shard_selection.rb +21 -58
- data/lib/active_record_shards/shard_support.rb +0 -1
- data/lib/active_record_shards/sharded_model.rb +15 -0
- data/lib/active_record_shards/sql_comments.rb +1 -5
- data/lib/active_record_shards/tasks.rb +19 -38
- metadata +52 -87
- data/lib/active_record_shards/connection_handler.rb +0 -8
- data/lib/active_record_shards/connection_pool.rb +0 -36
- data/lib/active_record_shards/connection_specification.rb +0 -19
- data/lib/active_record_shards/connection_switcher-4-2.rb +0 -56
- data/lib/active_record_shards/migration.rb +0 -125
- data/lib/active_record_shards/patches-4-2.rb +0 -9
- data/lib/active_record_shards/schema_dumper_extension.rb +0 -42
@@ -1,36 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module ActiveRecordShards
|
4
|
-
ConnectionPoolNameDecorator = Struct.new(:name)
|
5
|
-
|
6
|
-
# It overrides given connection handler methods (they differ depend on
|
7
|
-
# Rails version).
|
8
|
-
#
|
9
|
-
# It takes the first argument, ActiveRecord::Base object or
|
10
|
-
# String (connection_pool_name), converts it in Struct object and
|
11
|
-
# passes to the original method.
|
12
|
-
#
|
13
|
-
# Example:
|
14
|
-
# methods_to_override = [:establish_connection, :remove_connection]
|
15
|
-
# ActiveRecordShards.override_connection_handler_methods(methods_to_override)
|
16
|
-
#
|
17
|
-
def self.override_connection_handler_methods(method_names)
|
18
|
-
method_names.each do |method_name|
|
19
|
-
ActiveRecord::ConnectionAdapters::ConnectionHandler.class_eval do
|
20
|
-
define_method("#{method_name}_with_connection_pool_name") do |*args|
|
21
|
-
unless args[0].is_a? ConnectionPoolNameDecorator
|
22
|
-
name = if args[0].is_a? String
|
23
|
-
args[0]
|
24
|
-
else
|
25
|
-
args[0].connection_pool_name
|
26
|
-
end
|
27
|
-
args[0] = ConnectionPoolNameDecorator.new(name)
|
28
|
-
end
|
29
|
-
send("#{method_name}_without_connection_pool_name", *args)
|
30
|
-
end
|
31
|
-
alias_method :"#{method_name}_without_connection_pool_name", method_name
|
32
|
-
alias_method method_name, :"#{method_name}_with_connection_pool_name"
|
33
|
-
end
|
34
|
-
end
|
35
|
-
end
|
36
|
-
end
|
@@ -1,19 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
class << ActiveRecord::Base
|
4
|
-
remove_method :establish_connection if ActiveRecord::VERSION::MAJOR >= 5
|
5
|
-
def establish_connection(spec = ENV["DATABASE_URL"])
|
6
|
-
spec ||= ActiveRecord::ConnectionHandling::DEFAULT_ENV.call
|
7
|
-
spec = spec.to_sym if spec.is_a?(String)
|
8
|
-
resolver = ActiveRecordShards::ConnectionSpecification::Resolver.new configurations
|
9
|
-
spec = resolver.spec(spec)
|
10
|
-
|
11
|
-
unless respond_to?(spec.adapter_method)
|
12
|
-
raise AdapterNotFound, "database configuration specifies nonexistent #{spec.config[:adapter]} adapter"
|
13
|
-
end
|
14
|
-
|
15
|
-
remove_connection
|
16
|
-
specification_cache[connection_pool_name] = spec
|
17
|
-
connection_handler.establish_connection self, spec
|
18
|
-
end
|
19
|
-
end
|
@@ -1,56 +0,0 @@
|
|
1
|
-
module ActiveRecordShards
|
2
|
-
module ConnectionSwitcher
|
3
|
-
# Name of the connection pool. Used by ConnectionHandler to retrieve the current connection pool.
|
4
|
-
def connection_pool_name # :nodoc:
|
5
|
-
name = current_shard_selection.shard_name(self)
|
6
|
-
|
7
|
-
# e.g. if "production_slave" is not defined in `Configuration`, fall back to "production"
|
8
|
-
if configurations[name].nil? && on_slave?
|
9
|
-
current_shard_selection.shard_name(self, false)
|
10
|
-
else
|
11
|
-
name
|
12
|
-
end
|
13
|
-
end
|
14
|
-
|
15
|
-
private
|
16
|
-
|
17
|
-
def ensure_shard_connection
|
18
|
-
establish_shard_connection unless connected_to_shard?
|
19
|
-
end
|
20
|
-
|
21
|
-
def establish_shard_connection
|
22
|
-
name = connection_pool_name
|
23
|
-
spec = configurations[name]
|
24
|
-
|
25
|
-
if spec.nil?
|
26
|
-
raise ActiveRecord::AdapterNotSpecified, "No database defined by #{name} in your database config. (configurations: #{configurations.keys.inspect})"
|
27
|
-
end
|
28
|
-
|
29
|
-
specification_cache[name] ||= begin
|
30
|
-
resolver = ActiveRecordShards::ConnectionSpecification::Resolver.new configurations
|
31
|
-
resolver.spec(spec)
|
32
|
-
end
|
33
|
-
|
34
|
-
connection_handler.establish_connection(self, specification_cache[name])
|
35
|
-
end
|
36
|
-
|
37
|
-
def specification_cache
|
38
|
-
@@specification_cache ||= {}
|
39
|
-
end
|
40
|
-
|
41
|
-
# Helper method to clear global state when testing.
|
42
|
-
def clear_specification_cache
|
43
|
-
@@specification_cache = {}
|
44
|
-
end
|
45
|
-
|
46
|
-
def connection_pool_key
|
47
|
-
specification_cache[connection_pool_name]
|
48
|
-
end
|
49
|
-
|
50
|
-
def connected_to_shard?
|
51
|
-
specs_to_pools = Hash[connection_handler.connection_pool_list.map { |pool| [pool.spec, pool] }]
|
52
|
-
|
53
|
-
specs_to_pools.key?(connection_pool_key)
|
54
|
-
end
|
55
|
-
end
|
56
|
-
end
|
@@ -1,125 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module ActiveRecord
|
4
|
-
class Migrator
|
5
|
-
def self.shards_migration_context
|
6
|
-
if ActiveRecord::VERSION::MAJOR >= 6
|
7
|
-
ActiveRecord::MigrationContext.new(ActiveRecord::Migrator.migrations_paths, ActiveRecord::SchemaMigration)
|
8
|
-
elsif ActiveRecord::VERSION::STRING >= '5.2.0'
|
9
|
-
ActiveRecord::MigrationContext.new(ActiveRecord::Migrator.migrations_paths)
|
10
|
-
else
|
11
|
-
self
|
12
|
-
end
|
13
|
-
end
|
14
|
-
|
15
|
-
def initialize_with_sharding(*args)
|
16
|
-
initialize_without_sharding(*args)
|
17
|
-
|
18
|
-
# Rails creates the internal tables on the unsharded DB. We make them
|
19
|
-
# manually on the sharded DBs.
|
20
|
-
ActiveRecord::Base.on_all_shards do
|
21
|
-
ActiveRecord::SchemaMigration.create_table
|
22
|
-
if ActiveRecord::VERSION::MAJOR >= 5
|
23
|
-
ActiveRecord::InternalMetadata.create_table
|
24
|
-
end
|
25
|
-
end
|
26
|
-
end
|
27
|
-
alias_method :initialize_without_sharding, :initialize
|
28
|
-
alias_method :initialize, :initialize_with_sharding
|
29
|
-
|
30
|
-
def run_with_sharding
|
31
|
-
ActiveRecord::Base.on_shard(nil) { run_without_sharding }
|
32
|
-
ActiveRecord::Base.on_all_shards { run_without_sharding }
|
33
|
-
end
|
34
|
-
alias_method :run_without_sharding, :run
|
35
|
-
alias_method :run, :run_with_sharding
|
36
|
-
|
37
|
-
def migrate_with_sharding
|
38
|
-
ActiveRecord::Base.on_shard(nil) { migrate_without_sharding }
|
39
|
-
ActiveRecord::Base.on_all_shards { migrate_without_sharding }
|
40
|
-
end
|
41
|
-
alias_method :migrate_without_sharding, :migrate
|
42
|
-
alias_method :migrate, :migrate_with_sharding
|
43
|
-
|
44
|
-
# don't allow Migrator class to cache versions
|
45
|
-
undef migrated
|
46
|
-
def migrated
|
47
|
-
self.class.shards_migration_context.get_all_versions
|
48
|
-
end
|
49
|
-
|
50
|
-
# list of pending migrations is any migrations that haven't run on all shards.
|
51
|
-
undef pending_migrations
|
52
|
-
def pending_migrations
|
53
|
-
pending, _missing = self.class.shard_status(migrations.map(&:version))
|
54
|
-
pending = pending.values.flatten
|
55
|
-
migrations.select { |m| pending.include?(m.version) }
|
56
|
-
end
|
57
|
-
|
58
|
-
# public
|
59
|
-
# list of pending and missing versions per shard
|
60
|
-
# [{1 => [1234567]}, {1 => [2345678]}]
|
61
|
-
def self.shard_status(versions)
|
62
|
-
pending = {}
|
63
|
-
missing = {}
|
64
|
-
|
65
|
-
collect = lambda do |shard|
|
66
|
-
migrated = shards_migration_context.get_all_versions
|
67
|
-
|
68
|
-
p = versions - migrated
|
69
|
-
pending[shard] = p if p.any?
|
70
|
-
|
71
|
-
m = migrated - versions
|
72
|
-
missing[shard] = m if m.any?
|
73
|
-
end
|
74
|
-
|
75
|
-
ActiveRecord::Base.on_shard(nil) { collect.call(nil) }
|
76
|
-
ActiveRecord::Base.on_all_shards { |shard| collect.call(shard) }
|
77
|
-
|
78
|
-
[pending, missing]
|
79
|
-
end
|
80
|
-
end
|
81
|
-
end
|
82
|
-
|
83
|
-
module ActiveRecordShards
|
84
|
-
module MigrationClassExtension
|
85
|
-
attr_accessor :migration_shard
|
86
|
-
|
87
|
-
def shard(arg = nil)
|
88
|
-
self.migration_shard = arg
|
89
|
-
end
|
90
|
-
end
|
91
|
-
|
92
|
-
module ActualMigrationExtension
|
93
|
-
def migrate_with_forced_shard(direction)
|
94
|
-
if migration_shard.blank?
|
95
|
-
raise "#{name}: Can't run migrations without a shard spec: this may be :all, :none,
|
96
|
-
or a specific shard (for data-fixups). please call shard(arg) in your migration."
|
97
|
-
end
|
98
|
-
|
99
|
-
shard = ActiveRecord::Base.current_shard_selection.shard
|
100
|
-
|
101
|
-
if shard.nil?
|
102
|
-
return if migration_shard != :none
|
103
|
-
else
|
104
|
-
return if migration_shard == :none
|
105
|
-
return if migration_shard != :all && migration_shard.to_s != shard.to_s
|
106
|
-
end
|
107
|
-
|
108
|
-
migrate_without_forced_shard(direction)
|
109
|
-
end
|
110
|
-
|
111
|
-
def migration_shard
|
112
|
-
self.class.migration_shard
|
113
|
-
end
|
114
|
-
end
|
115
|
-
end
|
116
|
-
|
117
|
-
ActiveRecord::Migration.class_eval do
|
118
|
-
extend ActiveRecordShards::MigrationClassExtension
|
119
|
-
include ActiveRecordShards::ActualMigrationExtension
|
120
|
-
|
121
|
-
alias_method :migrate_without_forced_shard, :migrate
|
122
|
-
alias_method :migrate, :migrate_with_forced_shard
|
123
|
-
end
|
124
|
-
|
125
|
-
ActiveRecord::MigrationProxy.delegate :migration_shard, to: :migration
|
@@ -1,9 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'active_record_shards/connection_pool'
|
4
|
-
require 'active_record_shards/connection_handler'
|
5
|
-
require 'active_record_shards/connection_specification'
|
6
|
-
|
7
|
-
ActiveRecordShards::ConnectionSpecification = ActiveRecord::ConnectionAdapters::ConnectionSpecification
|
8
|
-
methods_to_override = [:establish_connection, :remove_connection, :pool_for, :pool_from_any_process_for]
|
9
|
-
ActiveRecordShards.override_connection_handler_methods(methods_to_override)
|
@@ -1,42 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module ActiveRecordShards
|
4
|
-
module SchemaDumperExtension
|
5
|
-
def dump(stream)
|
6
|
-
stream = super(stream)
|
7
|
-
original_connection = @connection
|
8
|
-
|
9
|
-
if ActiveRecord::Base.supports_sharding?
|
10
|
-
ActiveRecord::Base.on_first_shard do
|
11
|
-
@connection = ActiveRecord::Base.connection
|
12
|
-
shard_header(stream)
|
13
|
-
extensions(stream)
|
14
|
-
tables(stream)
|
15
|
-
shard_trailer(stream)
|
16
|
-
end
|
17
|
-
end
|
18
|
-
|
19
|
-
stream
|
20
|
-
ensure
|
21
|
-
@connection = original_connection
|
22
|
-
end
|
23
|
-
|
24
|
-
def shard_header(stream)
|
25
|
-
define_params = @version ? "version: #{@version}" : ""
|
26
|
-
|
27
|
-
stream.puts <<~HEADER
|
28
|
-
|
29
|
-
|
30
|
-
# This section generated by active_record_shards
|
31
|
-
|
32
|
-
ActiveRecord::Base.on_all_shards do
|
33
|
-
ActiveRecord::Schema.define(#{define_params}) do
|
34
|
-
|
35
|
-
HEADER
|
36
|
-
end
|
37
|
-
|
38
|
-
def shard_trailer(stream)
|
39
|
-
stream.puts "end\nend"
|
40
|
-
end
|
41
|
-
end
|
42
|
-
end
|