acts_as_partitionable 0.0.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.
- data/MIT-LICENSE +19 -0
- data/README +102 -0
- data/lib/acts_as_partitionable.rb +94 -0
- data/lib/connection_pool.rb +64 -0
- metadata +50 -0
data/MIT-LICENSE
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
Copyright (c) 2007 Revolution Health Group LLC
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
|
+
of this software and associated documentation files (the "Software"), to deal
|
5
|
+
in the Software without restriction, including without limitation the rights
|
6
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
7
|
+
copies of the Software, and to permit persons to whom the Software is
|
8
|
+
furnished to do so, subject to the following conditions:
|
9
|
+
|
10
|
+
The above copyright notice and this permission notice shall be included in
|
11
|
+
all copies or substantial portions of the Software.
|
12
|
+
|
13
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
16
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
17
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
18
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
19
|
+
THE SOFTWARE.
|
data/README
ADDED
@@ -0,0 +1,102 @@
|
|
1
|
+
== Introduction
|
2
|
+
|
3
|
+
ActsAsPartitionable provides support for using multiple databases to support
|
4
|
+
data partitioning schemes for existing models.
|
5
|
+
This plugin allows models marked as acts_as_partitionable to specify database
|
6
|
+
partitions to and explicit names to reference those partitions using existing
|
7
|
+
models. As part of this plugin connection pooling is provided so that many
|
8
|
+
different models may share the same database for partitions without forcing each
|
9
|
+
partition model object to inherit from a common base class.
|
10
|
+
|
11
|
+
== Disclaimer
|
12
|
+
|
13
|
+
As part of our strategy to address data partitioning as stated in our blog
|
14
|
+
entry:
|
15
|
+
http://revolutiononrails.blogspot.com/2007/04/ActsAsReadonlyable-to-support-
|
16
|
+
read-only.html
|
17
|
+
|
18
|
+
We wrote this plugin in preparation to using slave DBs but we are not going to
|
19
|
+
have those until May 2007.
|
20
|
+
So even though the code is covered with tests (see
|
21
|
+
svn://rubyforge.org/var/svn/actsaspartition/trunk/test/unit/partitionable_test.r
|
22
|
+
b), it has not yet been used in a production environment.
|
23
|
+
|
24
|
+
We will have a discovery period in May when the code is likely to be improved so
|
25
|
+
for now you can use is at your own risk.
|
26
|
+
Meanwhile, we would be happy to fix any issue revealed. Drop us a line at rails-
|
27
|
+
trunk [ at ] revolution DOT com.
|
28
|
+
|
29
|
+
Using this plugin should not be your first step in application
|
30
|
+
optimization/scaling or even the second one.
|
31
|
+
Before installing it make sure you understand the implication of leveraging
|
32
|
+
multiple DBs (for example, the potential for cross DB joins).
|
33
|
+
|
34
|
+
== Example
|
35
|
+
|
36
|
+
=== Sample Model
|
37
|
+
|
38
|
+
class SomeModel < ActiveRecord::Base
|
39
|
+
# use the read_only database from the database.yml
|
40
|
+
acts_as_partitionable :name => "partition_1", :access => :readonly,
|
41
|
+
:db_config => :read_only
|
42
|
+
|
43
|
+
# use the default database for partition_2
|
44
|
+
acts_as_partitionable :name => "partition_2"
|
45
|
+
|
46
|
+
# use the a specific w/r database for partition_3
|
47
|
+
acts_as_partitionable :name => "partition_3", :db_config =>
|
48
|
+
:some_model_partition
|
49
|
+
|
50
|
+
# Specify the database configuration from a hash
|
51
|
+
acts_as_partitionable :access => :readonly, :db_config => {:adapter =>
|
52
|
+
"mysql", :database => "partionable_db_test", :username => "root", :password =>
|
53
|
+
"", :host => "localhost"}
|
54
|
+
end
|
55
|
+
|
56
|
+
=== Sample DB Config
|
57
|
+
|
58
|
+
dbs:
|
59
|
+
|
60
|
+
database: master_db
|
61
|
+
host: master-host
|
62
|
+
|
63
|
+
read_only:
|
64
|
+
database: slave_db
|
65
|
+
host: slave-host
|
66
|
+
|
67
|
+
|
68
|
+
some_model_partition:
|
69
|
+
database: slave_db_2
|
70
|
+
host: slave-host
|
71
|
+
|
72
|
+
=== Usage
|
73
|
+
|
74
|
+
r = SomeModel.readonly.find(:first) # executes against the read_only db -
|
75
|
+
slave_db
|
76
|
+
r.field = 'value'
|
77
|
+
r.save! # raises ActiveRecord::ReadOnlyRecord
|
78
|
+
r.readonly? # true
|
79
|
+
|
80
|
+
t = SomeModel.partition_3.find(:first) # executes against slave_db_2
|
81
|
+
t.field = 'some value'
|
82
|
+
t.save! # success to partition_3
|
83
|
+
|
84
|
+
|
85
|
+
== Installation
|
86
|
+
|
87
|
+
As plugin:
|
88
|
+
script/plugin install
|
89
|
+
svn://rubyforge.org/var/svn/actsaspartition/trunk/vendor/plugins/acts_as_partiti
|
90
|
+
onable
|
91
|
+
|
92
|
+
|
93
|
+
== License
|
94
|
+
|
95
|
+
ActsAsPartitionable is released under the MIT license.
|
96
|
+
|
97
|
+
|
98
|
+
== Support
|
99
|
+
|
100
|
+
The plugin RubyForge page is http://rubyforge.org/projects/actsaspartition
|
101
|
+
|
102
|
+
|
@@ -0,0 +1,94 @@
|
|
1
|
+
# CONFIDENTIAL AND PROPRIETARY. © 2007 Revolution Health Group LLC. All rights reserved.
|
2
|
+
# This source code may not be disclosed to others, used or reproduced without the written permission of Revolution Health Group.
|
3
|
+
module Acts
|
4
|
+
module Partitionable
|
5
|
+
|
6
|
+
def self.included(base)
|
7
|
+
base.extend ClassMethods
|
8
|
+
end
|
9
|
+
|
10
|
+
module ClassMethods
|
11
|
+
def acts_as_partitionable?
|
12
|
+
true
|
13
|
+
end
|
14
|
+
|
15
|
+
# Readonly Simple Sample:
|
16
|
+
# class User
|
17
|
+
# acts_as_partitionable :access => :readonly, :db_config => ...
|
18
|
+
# end
|
19
|
+
# User.readonly do
|
20
|
+
# me = find(1) # DB hit
|
21
|
+
# end
|
22
|
+
# - or -
|
23
|
+
# User.readonly.find(:all)
|
24
|
+
#
|
25
|
+
#
|
26
|
+
# :access => [:readonly, :readwrite (default), :writeonly]
|
27
|
+
#
|
28
|
+
def acts_as_partitionable(options = {})
|
29
|
+
# default options
|
30
|
+
default_partition_name = "partition"
|
31
|
+
options = {:access => :readwrite, :name => default_partition_name}.merge(options)
|
32
|
+
|
33
|
+
partition_name = options[:name]
|
34
|
+
|
35
|
+
partition_db_klass_readonly = false
|
36
|
+
if options[:access] == :readonly
|
37
|
+
partition_db_klass_readonly = true
|
38
|
+
include ReadonlyInstanceMethods if partition_name == default_partition_name
|
39
|
+
end
|
40
|
+
|
41
|
+
if options[:db_config].is_a?(Hash)
|
42
|
+
db_config = options[:db_config]
|
43
|
+
elsif options[:db_config].is_a?(Symbol) or options[:db_config].is_a?(String)
|
44
|
+
begin
|
45
|
+
db_config = configurations[RAILS_ENV].merge(configurations[RAILS_ENV][options[:db_config].to_s])
|
46
|
+
rescue
|
47
|
+
raise ::ActiveRecord::ConfigurationError.new
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
partition_db_klass ||= eval <<-TOS
|
52
|
+
class #{self.name}Partitionable#{partition_name} < #{self.name}
|
53
|
+
# setting abstract_class to true so that ActiveRecord doesn't look
|
54
|
+
# for a db table for this base model class
|
55
|
+
self.abstract_class = true
|
56
|
+
def self.find_every(options)
|
57
|
+
(options ||= {})[:readonly] = true if #{partition_db_klass_readonly}
|
58
|
+
super(options)
|
59
|
+
end
|
60
|
+
def self.readonly?; #{partition_db_klass_readonly}; end
|
61
|
+
end
|
62
|
+
#{self.name}Partitionable#{partition_name}
|
63
|
+
TOS
|
64
|
+
partition_db_klass.establish_connection(db_config)
|
65
|
+
|
66
|
+
class_eval <<-PART_PROC_END
|
67
|
+
def self.#{partition_name}(&block)
|
68
|
+
return #{partition_db_klass}.module_eval(&block) if block_given?
|
69
|
+
#{partition_db_klass}
|
70
|
+
end
|
71
|
+
PART_PROC_END
|
72
|
+
end # acts_as_partitionable
|
73
|
+
|
74
|
+
|
75
|
+
module ReadonlyInstanceMethods #:nodoc:
|
76
|
+
def self.included(base) # :nodoc:
|
77
|
+
base.extend ClassMethods
|
78
|
+
end
|
79
|
+
|
80
|
+
module ClassMethods
|
81
|
+
|
82
|
+
def readonly(&block)
|
83
|
+
self.partition(&block)
|
84
|
+
end
|
85
|
+
|
86
|
+
end # ClassMethods
|
87
|
+
end # ReadonlyInstanceMethods
|
88
|
+
|
89
|
+
end # ClassMethods
|
90
|
+
|
91
|
+
end # Partitionable
|
92
|
+
end # Acts
|
93
|
+
|
94
|
+
ActiveRecord::Base.send :include, Acts::Partitionable
|
@@ -0,0 +1,64 @@
|
|
1
|
+
# CONFIDENTIAL AND PROPRIETARY. © 2007 Revolution Health Group LLC. All rights reserved.
|
2
|
+
# This source code may not be disclosed to others, used or reproduced without the written permission of Revolution Health Group.
|
3
|
+
module ActiveRecord
|
4
|
+
class Base
|
5
|
+
class << self
|
6
|
+
alias_method :no_cp_remove_connection, :remove_connection
|
7
|
+
alias_method :no_cp_establish_connection, :establish_connection
|
8
|
+
|
9
|
+
@@pooled_connections ||= {}
|
10
|
+
def pooled_connections
|
11
|
+
@@pooled_connections[Thread.current.object_id] ||= {}
|
12
|
+
end
|
13
|
+
|
14
|
+
def close_all_connections
|
15
|
+
pooled_connections.each do | key, value |
|
16
|
+
pooled_connections.delete(key)
|
17
|
+
active_connections.select { |klass, konn| no_cp_remove_connection(klass.constantize) if konn == value[:connection] }
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def remove_connection(klass=self)
|
22
|
+
konn = active_connections[klass.name]
|
23
|
+
conn_key = nil
|
24
|
+
pooled_connections.each { |key, value| conn_key = key if value != nil && value[:connection] == konn }
|
25
|
+
if conn_key != nil
|
26
|
+
pooled_connections[conn_key][:count] -= 1
|
27
|
+
if pooled_connections[conn_key][:count] > 0
|
28
|
+
# remove it from the active list so that AR wont disconnect until 0 references
|
29
|
+
active_connections.delete(klass.name)
|
30
|
+
else
|
31
|
+
# must be time to clean up.
|
32
|
+
pooled_connections.delete(conn_key)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
no_cp_remove_connection(klass)
|
36
|
+
end # remove_connection
|
37
|
+
|
38
|
+
def establish_connection(spec = nil)
|
39
|
+
if spec != nil and spec.kind_of?(ActiveRecord::Base::ConnectionSpecification)
|
40
|
+
@partitionable_adapter_methods ||= []
|
41
|
+
if not @partitionable_adapter_methods.include?(spec.adapter_method.to_s)
|
42
|
+
@partitionable_adapter_methods << (spec.adapter_method.to_s)
|
43
|
+
self.class_eval <<-REUSE_END
|
44
|
+
def self.#{spec.adapter_method}(config)
|
45
|
+
conn_key = config.to_s
|
46
|
+
if not pooled_connections.key?(conn_key)
|
47
|
+
pooled_connections[conn_key] = { :connection => super(config), :count => 1 }
|
48
|
+
elsif pooled_connections[conn_key] != nil
|
49
|
+
pooled_connections[conn_key][:count] += 1
|
50
|
+
end
|
51
|
+
pooled_connections[conn_key][:connection] rescue nil
|
52
|
+
end
|
53
|
+
REUSE_END
|
54
|
+
end
|
55
|
+
end
|
56
|
+
no_cp_establish_connection(spec)
|
57
|
+
end # establish_connection
|
58
|
+
end
|
59
|
+
end # Pool
|
60
|
+
end # Connection
|
61
|
+
|
62
|
+
#ActiveRecord::Base.send :include, Connection::Pool
|
63
|
+
#ActiveRecord::Base.extend Connection::Pool::ConnectionReuseMethods
|
64
|
+
|
metadata
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
rubygems_version: 0.9.0
|
3
|
+
specification_version: 1
|
4
|
+
name: acts_as_partitionable
|
5
|
+
version: !ruby/object:Gem::Version
|
6
|
+
version: 0.0.1
|
7
|
+
date: 2007-04-17 00:00:00 -04:00
|
8
|
+
summary: acts_as_partitionable allows one to use multiple DBs to partition data for models
|
9
|
+
require_paths:
|
10
|
+
- lib
|
11
|
+
email: rails-trunk@revolution.com
|
12
|
+
homepage:
|
13
|
+
rubyforge_project:
|
14
|
+
description:
|
15
|
+
autorequire:
|
16
|
+
default_executable:
|
17
|
+
bindir: bin
|
18
|
+
has_rdoc: false
|
19
|
+
required_ruby_version: !ruby/object:Gem::Version::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">"
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 0.0.0
|
24
|
+
version:
|
25
|
+
platform: ruby
|
26
|
+
signing_key:
|
27
|
+
cert_chain:
|
28
|
+
post_install_message:
|
29
|
+
authors:
|
30
|
+
- RHG Team
|
31
|
+
files:
|
32
|
+
- lib/acts_as_partitionable.rb
|
33
|
+
- lib/connection_pool.rb
|
34
|
+
- README
|
35
|
+
- MIT-LICENSE
|
36
|
+
test_files: []
|
37
|
+
|
38
|
+
rdoc_options: []
|
39
|
+
|
40
|
+
extra_rdoc_files:
|
41
|
+
- README
|
42
|
+
- MIT-LICENSE
|
43
|
+
executables: []
|
44
|
+
|
45
|
+
extensions: []
|
46
|
+
|
47
|
+
requirements: []
|
48
|
+
|
49
|
+
dependencies: []
|
50
|
+
|