active_shard 0.1.1 → 0.2.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/lib/active_shard/active_record/connection_handler.rb +74 -19
- data/lib/active_shard/active_record/connection_proxy_pool.rb +37 -0
- data/lib/active_shard/active_record/connection_specification_adapter.rb +27 -0
- data/lib/active_shard/active_record/schema_connection_proxy.rb +36 -0
- data/lib/active_shard/active_record.rb +12 -4
- data/lib/active_shard/config.rb +26 -30
- data/lib/active_shard/exceptions.rb +2 -1
- data/lib/active_shard/railtie.rb +64 -0
- data/lib/active_shard/scope.rb +3 -0
- data/lib/active_shard/scope_manager.rb +1 -1
- data/lib/active_shard/shard_collection.rb +17 -0
- data/lib/active_shard/shard_definition.rb +49 -8
- data/lib/active_shard/shard_lookup_handler.rb +7 -9
- data/lib/active_shard/version.rb +1 -1
- data/lib/active_shard.rb +98 -5
- metadata +19 -9
- data/CHANGELOG +0 -11
- data/lib/active_shard/active_record/railtie.rb +0 -56
- data/lib/active_shard/active_record/schema_connection_adapter.rb +0 -23
- data/lib/active_shard/active_record/schema_connection_pool.rb +0 -18
@@ -1,10 +1,9 @@
|
|
1
|
+
require 'active_record'
|
1
2
|
require 'active_record/connection_adapters/abstract/connection_pool'
|
2
3
|
|
3
4
|
module ActiveShard
|
4
5
|
module ActiveRecord
|
5
6
|
|
6
|
-
autoload :SchemaConnectionPool, 'active_shard/active_record/schema_connection_pool'
|
7
|
-
|
8
7
|
class ConnectionHandler < ::ActiveRecord::ConnectionAdapters::ConnectionHandler
|
9
8
|
|
10
9
|
# Used to look up shard names
|
@@ -15,54 +14,110 @@ module ActiveShard
|
|
15
14
|
#
|
16
15
|
# @param [Array<ShardDefinition>] shard_definitions
|
17
16
|
# @param [Hash] options
|
18
|
-
# @option options [ShardLookupHandler] :shard_lookup
|
17
|
+
# @option options [ShardLookupHandler, #lookup_active_shard] :shard_lookup
|
19
18
|
#
|
20
|
-
def initialize(
|
19
|
+
def initialize( options={} )
|
21
20
|
@shard_lookup = options[ :shard_lookup ]
|
22
21
|
|
22
|
+
@shard_definitions = []
|
23
23
|
@connection_pools = {}
|
24
24
|
@schema_pools = {}
|
25
|
+
end
|
25
26
|
|
26
|
-
|
27
|
+
# @api ShardObserver
|
28
|
+
def add_shards( shard_definitions )
|
29
|
+
shard_definitions.each( &method(:add_shard) )
|
27
30
|
end
|
28
31
|
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
32
|
+
# @api ShardObserver
|
33
|
+
def add_shard( shard_definition )
|
34
|
+
connection_pools[ connection_pool_id( shard_definition ) ] = new_connection_pool( shard_definition )
|
35
|
+
shard_definitions << shard_definition
|
36
|
+
|
37
|
+
self
|
38
|
+
end
|
34
39
|
|
40
|
+
# @api ShardObserver
|
41
|
+
def remove_shard( shard_definition )
|
42
|
+
schema_name = shard_definition.schema
|
35
43
|
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
44
|
+
# Remove SchemaPool if it's based on this shard
|
45
|
+
#
|
46
|
+
if ( schema_pools[ schema_name ] && schema_pools[ schema_name ].shard_definition == shard_definition )
|
47
|
+
schema_pools[ schema_name ].disconnect!
|
48
|
+
schema_pools.delete( schema_name )
|
40
49
|
end
|
50
|
+
|
51
|
+
pool_id = connection_pool_id( shard_definition )
|
52
|
+
|
53
|
+
# Remove connection pool
|
54
|
+
connection_pools[ pool_id ].disconnect!
|
55
|
+
connection_pools.delete( pool_id )
|
56
|
+
|
57
|
+
shard_definitions.delete( shard_definition )
|
58
|
+
|
59
|
+
self
|
60
|
+
end
|
61
|
+
|
62
|
+
# @api ShardObserver
|
63
|
+
def remove_all_shards!
|
64
|
+
defs = shard_definitions.dup
|
65
|
+
|
66
|
+
defs.each( &method(:remove_shard) )
|
41
67
|
end
|
42
68
|
|
69
|
+
# I want to put this in here, but it seems to cause problems that I haven't yet tracked down. [BLS]
|
70
|
+
#
|
43
71
|
#def establish_connection( *args )
|
44
72
|
# raise NoMethodError, "Sharded models do not support establish_connection"
|
45
73
|
#end
|
46
74
|
|
47
75
|
# Retrieve connection pool for class
|
48
76
|
#
|
77
|
+
# @param [#schema_name] klass An object which responds to #schema_name
|
78
|
+
# @return [ConnectionPool,SchemaConnectionPool] connection pool
|
79
|
+
#
|
49
80
|
def retrieve_connection_pool( klass )
|
50
|
-
schema_name = klass.schema_name
|
81
|
+
schema_name = ( sn = klass.schema_name ).nil? ? nil : sn.to_sym
|
51
82
|
|
52
83
|
active_shard_name = shard_lookup.lookup_active_shard( schema_name )
|
53
|
-
|
54
|
-
Rails.logger.debug( "RetrieveConnectionPool for #{klass.name}, schema_name #{schema_name}, active_shard #{active_shard_name}")
|
55
84
|
|
56
85
|
( active_shard_name.nil? ?
|
57
|
-
|
86
|
+
get_schema_pool_for( schema_name ) :
|
58
87
|
connection_pools[ connection_pool_id( schema_name, active_shard_name ) ] )
|
59
88
|
end
|
60
89
|
|
61
90
|
private
|
62
91
|
|
63
92
|
attr_reader :schema_pools
|
93
|
+
attr_reader :shard_definitions
|
94
|
+
|
95
|
+
def get_schema_pool_for( schema_name )
|
96
|
+
schema_name = schema_name.nil? ? nil : schema_name.to_sym
|
97
|
+
|
98
|
+
schema_pools[ schema_name ] ||= new_schema_pool( shard_definitions_for_schema( schema_name ).first )
|
99
|
+
end
|
100
|
+
|
101
|
+
def new_schema_pool( definition )
|
102
|
+
ConnectionProxyPool.new( definition, :proxy_class => SchemaConnectionProxy )
|
103
|
+
end
|
104
|
+
|
105
|
+
def new_connection_pool( definition )
|
106
|
+
ConnectionProxyPool.new( definition )
|
107
|
+
end
|
108
|
+
|
109
|
+
def shard_definitions_for_schema( schema_name )
|
110
|
+
shard_definitions.find_all { |sd| sd.belongs_to_schema?( schema_name ) }
|
111
|
+
end
|
112
|
+
|
113
|
+
# args are either a ShardDefinition or a schema and shard name.
|
114
|
+
#
|
115
|
+
def connection_pool_id( *args )
|
116
|
+
definition = args.first.is_a?( ShardDefinition ) ? args.shift : nil
|
117
|
+
|
118
|
+
schema_name = definition.nil? ? args.shift : definition.schema
|
119
|
+
shard_name = definition.nil? ? args.shift : definition.name
|
64
120
|
|
65
|
-
def connection_pool_id( schema_name, shard_name )
|
66
121
|
"#{schema_name.to_s}+#{shard_name.to_s}".to_sym
|
67
122
|
end
|
68
123
|
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'active_record'
|
2
|
+
require 'active_record/connection_adapters/abstract/connection_pool'
|
3
|
+
|
4
|
+
require 'active_shard/active_record/connection_specification_adapter'
|
5
|
+
|
6
|
+
module ActiveShard
|
7
|
+
module ActiveRecord
|
8
|
+
|
9
|
+
# ConnectionPool designed to return connection proxies of configurable types
|
10
|
+
#
|
11
|
+
class ConnectionProxyPool < ::ActiveRecord::ConnectionAdapters::ConnectionPool
|
12
|
+
|
13
|
+
attr_reader :shard_definition
|
14
|
+
|
15
|
+
# @param [ShardDefinition] definition
|
16
|
+
# @param [Hash] options
|
17
|
+
# @option options [Class] :proxy_class
|
18
|
+
#
|
19
|
+
def initialize( definition, options={} )
|
20
|
+
super( ConnectionSpecificationAdapter.new( definition ) )
|
21
|
+
|
22
|
+
@shard_definition = definition
|
23
|
+
@proxy_class = options[:proxy_class]
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
attr_reader :proxy_class
|
29
|
+
|
30
|
+
def new_connection
|
31
|
+
proxy_class.nil? ? super : proxy_class.new( super )
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module ActiveShard
|
2
|
+
module ActiveRecord
|
3
|
+
|
4
|
+
class ConnectionSpecificationAdapter
|
5
|
+
|
6
|
+
# @param [ShardDefinition] shard_definition
|
7
|
+
#
|
8
|
+
def initialize( shard_definition )
|
9
|
+
@shard_definition = shard_definition
|
10
|
+
end
|
11
|
+
|
12
|
+
def adapter_method
|
13
|
+
"#{shard_definition.connection_spec[:adapter]}_connection"
|
14
|
+
end
|
15
|
+
|
16
|
+
def config
|
17
|
+
shard_definition.connection_spec
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
attr_reader :shard_definition
|
23
|
+
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'active_support/core_ext/module/delegation'
|
2
|
+
require 'active_shard/exceptions'
|
3
|
+
|
4
|
+
module ActiveShard
|
5
|
+
module ActiveRecord
|
6
|
+
|
7
|
+
# SchemaConnectionProxy holds a Connection object and restricts messages passed
|
8
|
+
# to it. Only schema-ish messages are allowed.
|
9
|
+
#
|
10
|
+
class SchemaConnectionProxy
|
11
|
+
|
12
|
+
delegate :columns,
|
13
|
+
:verify,
|
14
|
+
:verify!,
|
15
|
+
:run_callbacks,
|
16
|
+
:_run_checkin_callbacks,
|
17
|
+
:quote_table_name,
|
18
|
+
:quote_value,
|
19
|
+
:disconnect!,
|
20
|
+
:quote, :to => :target
|
21
|
+
|
22
|
+
def initialize( target )
|
23
|
+
@target = target
|
24
|
+
end
|
25
|
+
|
26
|
+
def method_missing( sym, *args, &block )
|
27
|
+
raise ::ActiveShard::NoActiveShardError
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
def target
|
32
|
+
@target
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'active_record'
|
2
|
+
|
1
3
|
module ActiveShard
|
2
4
|
|
3
5
|
# The ActiveShard::ActiveRecord module contains the code necessary for ActiveRecord
|
@@ -6,10 +8,16 @@ module ActiveShard
|
|
6
8
|
# -- Need to add explanation of ShardedBase VS ShardSupport --
|
7
9
|
#
|
8
10
|
module ActiveRecord
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
11
|
+
extend ActiveSupport::Autoload
|
12
|
+
|
13
|
+
eager_autoload do
|
14
|
+
autoload :ConnectionHandler
|
15
|
+
autoload :ConnectionProxyPool
|
16
|
+
autoload :ConnectionSpecificationAdapter
|
17
|
+
autoload :SchemaConnectionProxy
|
18
|
+
autoload :ShardSupport
|
19
|
+
autoload :ShardedBase
|
20
|
+
end
|
13
21
|
|
14
22
|
end
|
15
23
|
end
|
data/lib/active_shard/config.rb
CHANGED
@@ -1,50 +1,46 @@
|
|
1
|
+
require 'active_shard/shard_collection'
|
2
|
+
|
1
3
|
module ActiveShard
|
2
|
-
autoload :ShardDefinition, 'active_shard/shard_definition'
|
3
|
-
autoload :ShardCollection, 'active_shard/shard_collection'
|
4
4
|
|
5
5
|
class Config
|
6
6
|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
shard_collection.by_schema( schema_name )
|
7
|
+
def shard_configuration=( configuration )
|
8
|
+
shard_collections.clear
|
9
|
+
|
10
|
+
configuration.each_pair do |environment, shard_definitions|
|
11
|
+
shard_collection( environment.to_sym ).add_shards( shard_definitions )
|
12
|
+
end
|
14
13
|
end
|
15
14
|
|
16
|
-
|
17
|
-
|
18
|
-
#
|
19
|
-
def schema_shard_name_by_schema( schema_name )
|
20
|
-
shard_def = shard_definitions_by_schema( schema_name ).first
|
21
|
-
|
22
|
-
shard_def.nil? ? nil : shard_def.name.to_sym
|
15
|
+
def shards_by_schema( environment, schema )
|
16
|
+
shard_collection( environment ).by_schema( schema )
|
23
17
|
end
|
24
18
|
|
25
|
-
|
26
|
-
|
27
|
-
# @return [ShardDefinition]
|
28
|
-
#
|
29
|
-
def shard( name )
|
30
|
-
shard_collection.shard( name )
|
19
|
+
def add_shard( environment, shard_definition )
|
20
|
+
shard_collection( environment ).add_shard( shard_definition )
|
31
21
|
end
|
32
22
|
|
33
|
-
def
|
34
|
-
shard_collection
|
23
|
+
def shard_definitions( environment )
|
24
|
+
shard_collection( environment )
|
35
25
|
end
|
36
26
|
|
37
|
-
def
|
38
|
-
shard_collection.
|
27
|
+
def remove_shard( environment, shard_name )
|
28
|
+
shard_collection( environment ).remove_shard( shard_name )
|
39
29
|
end
|
40
30
|
|
41
|
-
def
|
42
|
-
shard_collection.
|
31
|
+
def shard( environment, shard_name )
|
32
|
+
shard_collection( environment ).shard( shard_name )
|
43
33
|
end
|
44
34
|
|
45
35
|
private
|
46
|
-
def shard_collection
|
47
|
-
|
36
|
+
def shard_collection( enviro )
|
37
|
+
enviro = enviro.nil? ? nil : enviro.to_sym
|
38
|
+
|
39
|
+
shard_collections[ enviro ] ||= ShardCollection.new
|
40
|
+
end
|
41
|
+
|
42
|
+
def shard_collections
|
43
|
+
@shard_collections ||= {}
|
48
44
|
end
|
49
45
|
|
50
46
|
end
|
@@ -6,11 +6,12 @@ module ActiveShard
|
|
6
6
|
# than nesting.
|
7
7
|
#
|
8
8
|
|
9
|
+
# Base exception for all ActiveShard errors
|
10
|
+
#
|
9
11
|
class ActiveShardError < StandardError; end
|
10
12
|
|
11
13
|
class DefinitionError < ActiveShardError; end
|
12
14
|
class NameNotUniqueError < DefinitionError; end
|
13
|
-
|
14
15
|
class NoActiveShardError < ActiveShardError; end
|
15
16
|
|
16
17
|
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
require "active_shard"
|
2
|
+
|
3
|
+
module ActiveShard
|
4
|
+
class Railtie < Rails::Railtie
|
5
|
+
|
6
|
+
config.active_shard = ActiveSupport::OrderedOptions.new
|
7
|
+
|
8
|
+
rake_tasks do
|
9
|
+
load "active_shard/rails/database.rake"
|
10
|
+
end
|
11
|
+
|
12
|
+
initializer "active_shard.logger" do
|
13
|
+
ActiveSupport.on_load(:active_shard) { self.logger ||= ::Rails.logger }
|
14
|
+
end
|
15
|
+
|
16
|
+
initializer "active_shard.set_configs" do |app|
|
17
|
+
ActiveSupport.on_load(:active_shard) do
|
18
|
+
app.config.active_shard.each do |k,v|
|
19
|
+
send "#{k}=", v
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
initializer "active_shard.initialize_framework" do |app|
|
25
|
+
ActiveSupport.on_load(:active_shard) do
|
26
|
+
|
27
|
+
# TODO: Should anyone build code to plug ActiveShard into other ORMs, this
|
28
|
+
# Railtie could support that by respecting a configuration option.
|
29
|
+
#
|
30
|
+
# something like 'active_shard/data_mapper', 'active_shard/sequel'
|
31
|
+
#
|
32
|
+
require "active_shard/active_record"
|
33
|
+
|
34
|
+
::ActiveRecord::Base.send( :include, ActiveShard::ActiveRecord::ShardSupport )
|
35
|
+
::ActiveRecord::Base.schema_name( self.base_schema_name ) if self.base_schema_name
|
36
|
+
|
37
|
+
handler =
|
38
|
+
ActiveShard::ActiveRecord::ConnectionHandler.new(
|
39
|
+
:shard_lookup => ActiveShard::ShardLookupHandler.new( :scope => ActiveShard.scope )
|
40
|
+
)
|
41
|
+
|
42
|
+
self.shard_observers << handler
|
43
|
+
|
44
|
+
::ActiveRecord::Base.connection_handler = handler
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
initializer "active_shard.initialize_shard_configuration" do |app|
|
49
|
+
ActiveSupport.on_load(:active_shard) do
|
50
|
+
unless app.config.active_shard.shard_configuration
|
51
|
+
self.shard_configuration =
|
52
|
+
ActiveShard::ShardDefinition.from_yaml_file( Rails.root.join( "config", "shards.yml" ) )
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
initializer "active_shard.set_environment" do |app|
|
58
|
+
ActiveSupport.on_load(:active_shard) do
|
59
|
+
ActiveShard.environment = Rails.env.to_s
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
64
|
+
end
|
data/lib/active_shard/scope.rb
CHANGED
@@ -52,6 +52,9 @@ module ActiveShard
|
|
52
52
|
|
53
53
|
# Remove the last scope from the stack
|
54
54
|
#
|
55
|
+
# FIXME: Symbols (for AnySchema) may not roll back properly if multiple
|
56
|
+
# the same symbol is on the stack several times
|
57
|
+
#
|
55
58
|
def pop( pop_until=nil )
|
56
59
|
if pop_until.nil?
|
57
60
|
scope_crumbs.pop
|
@@ -11,6 +11,7 @@ module ActiveShard
|
|
11
11
|
# in most situations.
|
12
12
|
#
|
13
13
|
class ShardCollection
|
14
|
+
include Enumerable
|
14
15
|
|
15
16
|
# Initializes a shard group
|
16
17
|
#
|
@@ -84,6 +85,10 @@ module ActiveShard
|
|
84
85
|
self.class.new( definitions_by_schema( schema_name ) )
|
85
86
|
end
|
86
87
|
|
88
|
+
def schemas
|
89
|
+
definitions.map { |d| d.schema }.uniq.compact
|
90
|
+
end
|
91
|
+
|
87
92
|
# Removes a shard definition from the collection based on the
|
88
93
|
# provided shard name.
|
89
94
|
#
|
@@ -118,6 +123,18 @@ module ActiveShard
|
|
118
123
|
def any_shard
|
119
124
|
definitions[ rand( definitions.size ) ].name
|
120
125
|
end
|
126
|
+
|
127
|
+
def each( &block )
|
128
|
+
definitions.each( &block )
|
129
|
+
end
|
130
|
+
|
131
|
+
def length
|
132
|
+
definitions.length
|
133
|
+
end
|
134
|
+
|
135
|
+
def size
|
136
|
+
length
|
137
|
+
end
|
121
138
|
|
122
139
|
private
|
123
140
|
|
@@ -1,9 +1,10 @@
|
|
1
|
+
require 'active_support/hash_with_indifferent_access'
|
2
|
+
|
1
3
|
module ActiveShard
|
2
4
|
|
3
5
|
class ShardDefinition
|
4
6
|
attr_accessor :schema
|
5
7
|
attr_accessor :name
|
6
|
-
attr_writer :connection_spec
|
7
8
|
|
8
9
|
class << self
|
9
10
|
|
@@ -15,9 +16,31 @@ module ActiveShard
|
|
15
16
|
# @return [Hash] hash of environments and lists of Definitions
|
16
17
|
#
|
17
18
|
def from_yaml_file( file_name )
|
18
|
-
|
19
|
+
from_yaml( File.open( file_name ).read() )
|
20
|
+
end
|
19
21
|
|
20
|
-
|
22
|
+
# Returns a hash with environments as the hash keys and
|
23
|
+
# a list of ShardDefinitions as the hash values
|
24
|
+
#
|
25
|
+
# @param [String] yaml YAML string to parse
|
26
|
+
#
|
27
|
+
# @return [Hash] hash of environments and lists of Definitions
|
28
|
+
#
|
29
|
+
def from_yaml( yaml )
|
30
|
+
hash = YAML.load( ERB.new( yaml ).result )
|
31
|
+
|
32
|
+
from_hash( hash )
|
33
|
+
end
|
34
|
+
|
35
|
+
# Returns a hash with environments as the hash keys and
|
36
|
+
# a list of ShardDefinitions as the hash values
|
37
|
+
#
|
38
|
+
# @param [Hash] hash raw hash in YAML-format
|
39
|
+
#
|
40
|
+
# @return [Hash] hash of environments and lists of Definitions
|
41
|
+
#
|
42
|
+
def from_hash( hash )
|
43
|
+
definitions = {}
|
21
44
|
|
22
45
|
hash.each_pair do |environment, schemas|
|
23
46
|
schemas.each_pair do |schema, shards|
|
@@ -44,13 +67,21 @@ module ActiveShard
|
|
44
67
|
def initialize( name, options={} )
|
45
68
|
opts = options.dup
|
46
69
|
|
47
|
-
@name
|
48
|
-
@schema
|
49
|
-
|
70
|
+
@name = name.to_sym
|
71
|
+
@schema = ( ( sch = opts.delete( :schema ) ).nil? ? nil : sch.to_sym )
|
72
|
+
self.connection_spec = opts
|
50
73
|
end
|
51
74
|
|
52
|
-
def
|
53
|
-
|
75
|
+
def connection_adapter
|
76
|
+
@connection_adapter ||= connection_spec[:adapter]
|
77
|
+
end
|
78
|
+
|
79
|
+
def connection_database
|
80
|
+
@connection_database ||= connection_spec[:database]
|
81
|
+
end
|
82
|
+
|
83
|
+
def connection_spec=(val)
|
84
|
+
@connection_spec = val.nil? ? nil : HashWithIndifferentAccess.new( val )
|
54
85
|
end
|
55
86
|
|
56
87
|
def connection_spec
|
@@ -70,6 +101,16 @@ module ActiveShard
|
|
70
101
|
( schema.to_sym == schema_name.to_sym )
|
71
102
|
end
|
72
103
|
|
104
|
+
def ==( other )
|
105
|
+
eql?( other )
|
106
|
+
end
|
107
|
+
|
108
|
+
def eql?( other )
|
109
|
+
(self.name == other.name) &&
|
110
|
+
(self.schema == other.schema) &&
|
111
|
+
(self.connection_spec == other.connection_spec)
|
112
|
+
end
|
113
|
+
|
73
114
|
private
|
74
115
|
|
75
116
|
def symbolize_keys( hash )
|
@@ -1,28 +1,26 @@
|
|
1
1
|
module ActiveShard
|
2
2
|
|
3
|
-
# Handles current
|
4
|
-
#
|
3
|
+
# Handles current shard resolution using the provided scope
|
4
|
+
#
|
5
5
|
class ShardLookupHandler
|
6
6
|
|
7
7
|
# Initializes a shard lookup handler
|
8
8
|
#
|
9
9
|
# @param [Hash] options
|
10
10
|
# @option options [Scope,ScopeManager] :scope
|
11
|
-
# @option options [Config] :config
|
12
|
-
# scope instances
|
13
11
|
#
|
14
12
|
def initialize( options={} )
|
15
13
|
@scope = options[:scope]
|
16
|
-
@config = options[:config]
|
17
14
|
end
|
18
15
|
|
16
|
+
# Returns the active shard for the provided schema, or nil if none.
|
17
|
+
#
|
18
|
+
# @param [Symbol] schema_name
|
19
|
+
# @return [Symbol, nil] shard name if any
|
20
|
+
#
|
19
21
|
def lookup_active_shard( schema_name )
|
20
22
|
@scope.active_shard_for_schema( schema_name )
|
21
23
|
end
|
22
24
|
|
23
|
-
def lookup_schema_shard( schema_name )
|
24
|
-
@config.schema_shard_name_by_schema( schema_name )
|
25
|
-
end
|
26
|
-
|
27
25
|
end
|
28
26
|
end
|
data/lib/active_shard/version.rb
CHANGED
data/lib/active_shard.rb
CHANGED
@@ -1,19 +1,45 @@
|
|
1
|
+
require 'active_support'
|
2
|
+
|
1
3
|
module ActiveShard
|
4
|
+
extend ActiveSupport::Autoload
|
2
5
|
|
3
|
-
autoload :Config
|
4
|
-
autoload :
|
5
|
-
autoload :
|
6
|
-
autoload :ShardCollection
|
6
|
+
autoload :Config
|
7
|
+
autoload :Scope
|
8
|
+
autoload :ScopeManager
|
9
|
+
autoload :ShardCollection
|
10
|
+
autoload :ShardDefinition
|
11
|
+
autoload :ShardLookupHandler
|
7
12
|
|
8
13
|
class << self
|
9
14
|
|
15
|
+
def with_environment( val )
|
16
|
+
previous_environment = self.environment
|
17
|
+
self.environment = val
|
18
|
+
|
19
|
+
yield
|
20
|
+
|
21
|
+
self.environment = previous_environment
|
22
|
+
end
|
23
|
+
|
24
|
+
def environment=( val )
|
25
|
+
env_changed = !( @environment.to_s == val.to_s )
|
26
|
+
|
27
|
+
@environment = val.nil? ? nil : val.to_sym
|
28
|
+
|
29
|
+
reload_observer_shards! if env_changed
|
30
|
+
end
|
31
|
+
|
32
|
+
def environment
|
33
|
+
@environment
|
34
|
+
end
|
35
|
+
|
10
36
|
# Returns the current Config object for ActiveShard.
|
11
37
|
#
|
12
38
|
# @yield [c] yields the current config object to the block for setup
|
13
39
|
#
|
14
40
|
# @return [Config] current config
|
15
41
|
#
|
16
|
-
def config
|
42
|
+
def config
|
17
43
|
@config ||= Config.new
|
18
44
|
|
19
45
|
yield( @config ) if block_given?
|
@@ -21,6 +47,68 @@ module ActiveShard
|
|
21
47
|
@config
|
22
48
|
end
|
23
49
|
|
50
|
+
def base_schema_name=(val)
|
51
|
+
@base_schema_name = val.nil? ? nil : val.to_sym
|
52
|
+
end
|
53
|
+
|
54
|
+
def base_schema_name
|
55
|
+
@base_schema_name
|
56
|
+
end
|
57
|
+
|
58
|
+
def shard_configuration=( configuration )
|
59
|
+
config.shard_configuration=( configuration )
|
60
|
+
|
61
|
+
reload_observer_shards!
|
62
|
+
end
|
63
|
+
|
64
|
+
# Doesn't yet support anything other than ActiveRecord::Base
|
65
|
+
#
|
66
|
+
#def base_class=(val)
|
67
|
+
# @base_class = val
|
68
|
+
#end
|
69
|
+
#
|
70
|
+
#def base_class
|
71
|
+
# @base_class
|
72
|
+
#end
|
73
|
+
|
74
|
+
def notify_shard_observers( message, *args )
|
75
|
+
shard_observers.each do |observer|
|
76
|
+
observer.public_send( message, *args ) if observer.respond_to?( message )
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def add_shard_observer( observer )
|
81
|
+
shard_observers << observer
|
82
|
+
end
|
83
|
+
|
84
|
+
def shard_observers
|
85
|
+
@shard_observers ||= []
|
86
|
+
end
|
87
|
+
|
88
|
+
def add_shard( *args )
|
89
|
+
definition = args.first.is_a?( ShardDefinition ) ? args.first : ShardDefinition.new( *args )
|
90
|
+
|
91
|
+
config.add_shard( environment, definition )
|
92
|
+
|
93
|
+
notify_shard_observers( :add_shard, definition )
|
94
|
+
|
95
|
+
definition
|
96
|
+
end
|
97
|
+
|
98
|
+
def remove_shard( shard_name )
|
99
|
+
config.remove_shard( environment, shard_name )
|
100
|
+
|
101
|
+
notify_shard_observers( :remove_shard, shard_name )
|
102
|
+
end
|
103
|
+
|
104
|
+
def shard_definitions
|
105
|
+
config.shard_definitions( environment )
|
106
|
+
end
|
107
|
+
|
108
|
+
def shard( shard_name )
|
109
|
+
config.shard( environment, shard_name )
|
110
|
+
end
|
111
|
+
|
24
112
|
# Sets the current scope handling object.
|
25
113
|
#
|
26
114
|
# Scope handler must respond to the following methods:
|
@@ -92,6 +180,11 @@ module ActiveShard
|
|
92
180
|
@logger = val
|
93
181
|
end
|
94
182
|
|
183
|
+
def reload_observer_shards!
|
184
|
+
notify_shard_observers( :remove_all_shards! )
|
185
|
+
notify_shard_observers( :add_shards, shard_definitions )
|
186
|
+
end
|
187
|
+
|
95
188
|
end
|
96
189
|
end
|
97
190
|
|
metadata
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
name: active_shard
|
3
3
|
version: !ruby/object:Gem::Version
|
4
4
|
prerelease:
|
5
|
-
version: 0.
|
5
|
+
version: 0.2.0
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- Brasten Sager
|
@@ -11,9 +11,19 @@ autorequire:
|
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
13
|
|
14
|
-
date: 2011-08-
|
15
|
-
dependencies:
|
16
|
-
|
14
|
+
date: 2011-08-19 00:00:00 Z
|
15
|
+
dependencies:
|
16
|
+
- !ruby/object:Gem::Dependency
|
17
|
+
name: activesupport
|
18
|
+
prerelease: false
|
19
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
20
|
+
none: false
|
21
|
+
requirements:
|
22
|
+
- - ~>
|
23
|
+
- !ruby/object:Gem::Version
|
24
|
+
version: 3.0.0
|
25
|
+
type: :runtime
|
26
|
+
version_requirements: *id001
|
17
27
|
description: ActiveShard is a library that implements flexible sharding in ActiveRecord and Rails.
|
18
28
|
email:
|
19
29
|
- brasten@dashwire.com
|
@@ -25,17 +35,17 @@ extensions: []
|
|
25
35
|
extra_rdoc_files: []
|
26
36
|
|
27
37
|
files:
|
28
|
-
- CHANGELOG
|
29
38
|
- README.md
|
30
39
|
- lib/active_shard/active_record/connection_handler.rb
|
31
|
-
- lib/active_shard/active_record/
|
32
|
-
- lib/active_shard/active_record/
|
33
|
-
- lib/active_shard/active_record/
|
40
|
+
- lib/active_shard/active_record/connection_proxy_pool.rb
|
41
|
+
- lib/active_shard/active_record/connection_specification_adapter.rb
|
42
|
+
- lib/active_shard/active_record/schema_connection_proxy.rb
|
34
43
|
- lib/active_shard/active_record/shard_support.rb
|
35
44
|
- lib/active_shard/active_record/sharded_base.rb
|
36
45
|
- lib/active_shard/active_record.rb
|
37
46
|
- lib/active_shard/config.rb
|
38
47
|
- lib/active_shard/exceptions.rb
|
48
|
+
- lib/active_shard/railtie.rb
|
39
49
|
- lib/active_shard/scope.rb
|
40
50
|
- lib/active_shard/scope_manager.rb
|
41
51
|
- lib/active_shard/shard_collection.rb
|
@@ -43,7 +53,7 @@ files:
|
|
43
53
|
- lib/active_shard/shard_lookup_handler.rb
|
44
54
|
- lib/active_shard/version.rb
|
45
55
|
- lib/active_shard.rb
|
46
|
-
homepage:
|
56
|
+
homepage: https://github.com/dashwire/active_shard
|
47
57
|
licenses: []
|
48
58
|
|
49
59
|
post_install_message:
|
data/CHANGELOG
DELETED
@@ -1,56 +0,0 @@
|
|
1
|
-
require "active_shard"
|
2
|
-
require "rails"
|
3
|
-
|
4
|
-
module ActiveShard
|
5
|
-
module ActiveRecord
|
6
|
-
class Railtie < Rails::Railtie
|
7
|
-
|
8
|
-
config.active_shard = ActiveSupport::OrderedOptions.new
|
9
|
-
|
10
|
-
rake_tasks do
|
11
|
-
load "active_shard/active_record/rails/database.rake"
|
12
|
-
end
|
13
|
-
|
14
|
-
initializer "active_shard.logger" do
|
15
|
-
ActiveSupport.on_load(:active_shard) { self.logger ||= ::Rails.logger }
|
16
|
-
end
|
17
|
-
|
18
|
-
initializer "active_shard.set_configs" do |app|
|
19
|
-
ActiveSupport.on_load(:active_record) do
|
20
|
-
app.config.active_record.each do |k,v|
|
21
|
-
send "#{k}=", v
|
22
|
-
end
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
|
-
initializer "active_shard.initialize_database" do |app|
|
27
|
-
ActiveSupport.on_load(:active_record) do
|
28
|
-
self.configurations = app.config.database_configuration
|
29
|
-
establish_connection
|
30
|
-
end
|
31
|
-
end
|
32
|
-
|
33
|
-
# ActiveShard.config do |c|
|
34
|
-
# definitions = ActiveShard::ShardDefinition.from_yaml_file( File.expand_path( '../shards.yml', __FILE__ ) )
|
35
|
-
#
|
36
|
-
# definitions[ Rails.env.to_sym ].each do |shard|
|
37
|
-
# c.add_shard( shard )
|
38
|
-
# end
|
39
|
-
# end
|
40
|
-
#
|
41
|
-
# require 'active_shard/active_record'
|
42
|
-
#
|
43
|
-
# ActiveRecord::Base.send( :include, ActiveShard::ActiveRecord::ShardSupport )
|
44
|
-
#
|
45
|
-
# ActiveRecord::Base.connection_handler =
|
46
|
-
# ActiveShard::ActiveRecord::ConnectionHandler.new(
|
47
|
-
# ActiveShard.config.shard_definitions,
|
48
|
-
# :shard_lookup => ActiveShard::ShardLookupHandler.new( :scope => ActiveShard.scope, :config => ActiveShard.config )
|
49
|
-
# )
|
50
|
-
#
|
51
|
-
# ActiveRecord::Base.schema_name( :main )
|
52
|
-
|
53
|
-
|
54
|
-
end
|
55
|
-
end
|
56
|
-
end
|
@@ -1,23 +0,0 @@
|
|
1
|
-
require 'active_shard/exceptions'
|
2
|
-
|
3
|
-
module ActiveShard
|
4
|
-
module ActiveRecord
|
5
|
-
class SchemaConnectionAdapter
|
6
|
-
|
7
|
-
delegate :columns, :verify, :verify!, :run_callbacks, :quote_table_name, :quote_value, :quote, :to => :adapter
|
8
|
-
|
9
|
-
def initialize( adapter )
|
10
|
-
@adapter = adapter
|
11
|
-
end
|
12
|
-
|
13
|
-
def method_missing( sym, *args, &block )
|
14
|
-
raise ::ActiveShard::NoActiveShardError
|
15
|
-
end
|
16
|
-
|
17
|
-
private
|
18
|
-
def adapter
|
19
|
-
@adapter
|
20
|
-
end
|
21
|
-
end
|
22
|
-
end
|
23
|
-
end
|
@@ -1,18 +0,0 @@
|
|
1
|
-
require 'active_record/connection_adapters/abstract/connection_pool'
|
2
|
-
|
3
|
-
module ActiveShard
|
4
|
-
module ActiveRecord
|
5
|
-
|
6
|
-
autoload :SchemaConnectionAdapter, 'active_shard/active_record/schema_connection_adapter'
|
7
|
-
|
8
|
-
class SchemaConnectionPool < ::ActiveRecord::ConnectionAdapters::ConnectionPool
|
9
|
-
|
10
|
-
private
|
11
|
-
def new_connection
|
12
|
-
SchemaConnectionAdapter.new( super )
|
13
|
-
end
|
14
|
-
|
15
|
-
end
|
16
|
-
|
17
|
-
end
|
18
|
-
end
|