ar-octopus 0.8.1 → 0.10.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (109) hide show
  1. checksums.yaml +6 -14
  2. data/.gitignore +1 -0
  3. data/.rspec +1 -1
  4. data/.rubocop.yml +46 -0
  5. data/.rubocop_todo.yml +56 -0
  6. data/.travis.yml +7 -12
  7. data/Appraisals +11 -4
  8. data/Gemfile +1 -1
  9. data/README.mkdn +138 -63
  10. data/Rakefile +23 -16
  11. data/ar-octopus.gemspec +23 -20
  12. data/gemfiles/rails42.gemfile +7 -0
  13. data/gemfiles/{rails32.gemfile → rails5.gemfile} +2 -2
  14. data/gemfiles/{rails4.gemfile → rails51.gemfile} +2 -2
  15. data/gemfiles/rails52.gemfile +7 -0
  16. data/lib/ar-octopus.rb +1 -1
  17. data/lib/octopus/{rails3/abstract_adapter.rb → abstract_adapter.rb} +4 -15
  18. data/lib/octopus/association.rb +8 -99
  19. data/lib/octopus/association_shard_tracking.rb +74 -0
  20. data/lib/octopus/collection_association.rb +17 -0
  21. data/lib/octopus/collection_proxy.rb +16 -0
  22. data/lib/octopus/exception.rb +4 -0
  23. data/lib/octopus/finder_methods.rb +8 -0
  24. data/lib/octopus/load_balancing/round_robin.rb +20 -0
  25. data/lib/octopus/load_balancing.rb +4 -0
  26. data/lib/octopus/{rails3/log_subscriber.rb → log_subscriber.rb} +6 -2
  27. data/lib/octopus/migration.rb +187 -110
  28. data/lib/octopus/model.rb +151 -131
  29. data/lib/octopus/persistence.rb +45 -0
  30. data/lib/octopus/proxy.rb +297 -232
  31. data/lib/octopus/proxy_config.rb +251 -0
  32. data/lib/octopus/query_cache_for_shards.rb +24 -0
  33. data/lib/octopus/railtie.rb +1 -3
  34. data/lib/octopus/relation_proxy.rb +70 -0
  35. data/lib/octopus/result_patch.rb +19 -0
  36. data/lib/octopus/scope_proxy.rb +54 -36
  37. data/lib/octopus/shard_tracking/attribute.rb +22 -0
  38. data/lib/octopus/shard_tracking/dynamic.rb +11 -0
  39. data/lib/octopus/shard_tracking.rb +46 -0
  40. data/lib/octopus/singular_association.rb +9 -0
  41. data/lib/octopus/slave_group.rb +13 -0
  42. data/lib/octopus/version.rb +1 -1
  43. data/lib/octopus.rb +125 -33
  44. data/lib/tasks/octopus.rake +2 -2
  45. data/sample_app/Gemfile +3 -3
  46. data/sample_app/autotest/discover.rb +2 -2
  47. data/sample_app/config/application.rb +1 -1
  48. data/sample_app/config/boot.rb +1 -1
  49. data/sample_app/config/environments/test.rb +1 -1
  50. data/sample_app/config/initializers/session_store.rb +1 -1
  51. data/sample_app/config/initializers/wrap_parameters.rb +1 -1
  52. data/sample_app/config/routes.rb +1 -1
  53. data/sample_app/db/migrate/20100720210335_create_sample_users.rb +2 -2
  54. data/sample_app/db/schema.rb +10 -10
  55. data/sample_app/db/seeds.rb +3 -3
  56. data/sample_app/features/step_definitions/seeds_steps.rb +4 -4
  57. data/sample_app/features/step_definitions/web_steps.rb +3 -4
  58. data/sample_app/features/support/env.rb +3 -4
  59. data/sample_app/features/support/paths.rb +4 -4
  60. data/sample_app/lib/tasks/cucumber.rake +43 -44
  61. data/sample_app/spec/spec_helper.rb +3 -3
  62. data/spec/config/shards.yml +78 -0
  63. data/spec/migrations/10_create_users_using_replication.rb +4 -4
  64. data/spec/migrations/11_add_field_in_all_slaves.rb +4 -4
  65. data/spec/migrations/12_create_users_using_block.rb +8 -8
  66. data/spec/migrations/13_create_users_using_block_and_using.rb +5 -5
  67. data/spec/migrations/14_create_users_on_shards_of_a_group_with_versions.rb +3 -3
  68. data/spec/migrations/15_create_user_on_shards_of_default_group_with_versions.rb +3 -3
  69. data/spec/migrations/1_create_users_on_master.rb +4 -4
  70. data/spec/migrations/2_create_users_on_canada.rb +4 -4
  71. data/spec/migrations/3_create_users_on_both_shards.rb +4 -4
  72. data/spec/migrations/4_create_users_on_shards_of_a_group.rb +4 -4
  73. data/spec/migrations/5_create_users_on_multiples_groups.rb +3 -3
  74. data/spec/migrations/6_raise_exception_with_invalid_shard_name.rb +4 -4
  75. data/spec/migrations/7_raise_exception_with_invalid_multiple_shard_names.rb +4 -4
  76. data/spec/migrations/8_raise_exception_with_invalid_group_name.rb +4 -4
  77. data/spec/migrations/9_raise_exception_with_multiple_invalid_group_names.rb +5 -5
  78. data/spec/octopus/association_shard_tracking_spec.rb +1036 -0
  79. data/spec/octopus/collection_proxy_spec.rb +16 -0
  80. data/spec/octopus/load_balancing/round_robin_spec.rb +15 -0
  81. data/spec/octopus/log_subscriber_spec.rb +5 -5
  82. data/spec/octopus/migration_spec.rb +83 -49
  83. data/spec/octopus/model_spec.rb +544 -292
  84. data/spec/octopus/octopus_spec.rb +64 -31
  85. data/spec/octopus/proxy_spec.rb +145 -141
  86. data/spec/octopus/query_cache_for_shards_spec.rb +40 -0
  87. data/spec/octopus/relation_proxy_spec.rb +132 -0
  88. data/spec/octopus/replicated_slave_grouped_spec.rb +91 -0
  89. data/spec/octopus/replication_spec.rb +140 -65
  90. data/spec/octopus/scope_proxy_spec.rb +90 -10
  91. data/spec/octopus/sharded_replicated_slave_grouped_spec.rb +55 -0
  92. data/spec/octopus/sharded_spec.rb +10 -10
  93. data/spec/spec_helper.rb +8 -6
  94. data/spec/support/active_record/connection_adapters/modify_config_adapter.rb +1 -3
  95. data/spec/support/database_connection.rb +2 -2
  96. data/spec/support/database_models.rb +18 -17
  97. data/spec/support/octopus_helper.rb +32 -25
  98. data/spec/support/query_count.rb +1 -3
  99. data/spec/support/shared_contexts.rb +3 -3
  100. data/spec/tasks/octopus.rake_spec.rb +10 -10
  101. metadata +112 -70
  102. data/.ruby-version +0 -1
  103. data/init.rb +0 -1
  104. data/lib/octopus/association_collection.rb +0 -49
  105. data/lib/octopus/has_and_belongs_to_many_association.rb +0 -17
  106. data/lib/octopus/rails3/persistence.rb +0 -39
  107. data/lib/octopus/rails3/singular_association.rb +0 -34
  108. data/rails/init.rb +0 -1
  109. data/spec/octopus/association_spec.rb +0 -712
@@ -1,155 +1,232 @@
1
- require "set"
2
- require "active_support/core_ext/module/aliasing"
3
- require "active_support/core_ext/array/wrap"
4
-
5
- module Octopus::Migration
6
- module InstanceOrClassMethods
7
- def announce_with_octopus(message)
8
- announce_without_octopus("#{message} - #{get_current_shard}")
9
- end
1
+ require 'set'
2
+ require 'active_support/core_ext/module/aliasing'
3
+ require 'active_support/core_ext/array/wrap'
4
+
5
+ module Octopus
6
+ module Migration
7
+ module InstanceOrClassMethods
8
+ def announce_with_octopus(message)
9
+ announce_without_octopus("#{message} - #{current_shard}")
10
+ end
10
11
 
11
- def get_current_shard
12
- "Shard: #{connection.current_shard}" if connection.respond_to?(:current_shard)
12
+ def current_shard
13
+ "Shard: #{connection.current_shard}" if connection.respond_to?(:current_shard)
14
+ end
13
15
  end
14
- end
15
16
 
16
- include InstanceOrClassMethods
17
+ include InstanceOrClassMethods
17
18
 
18
- def self.included(base)
19
- base.extend(ClassMethods)
19
+ def self.included(base)
20
+ base.extend(ClassMethods)
20
21
 
21
- base.alias_method_chain :announce, :octopus
22
- base.class_attribute :current_shard, :current_group, :current_group_specified, :instance_reader => false, :instance_writer => false
23
- end
24
-
25
- module ClassMethods
26
- def using(*args)
27
- return self unless connection.is_a?(Octopus::Proxy)
22
+ base.send :alias_method, :announce_without_octopus, :announce
23
+ base.send :alias_method, :announce, :announce_with_octopus
28
24
 
29
- self.current_shard = args
30
- self
25
+ base.class_attribute :current_shard, :current_group, :current_group_specified, :instance_reader => false, :instance_writer => false
31
26
  end
32
27
 
33
- def using_group(*groups)
34
- return self unless connection.is_a?(Octopus::Proxy)
28
+ module ClassMethods
29
+ def using(*args)
30
+ return self unless connection.is_a?(Octopus::Proxy)
35
31
 
36
- self.current_group = groups
37
- self.current_group_specified = true
38
- self
39
- end
32
+ self.current_shard = args
33
+ self
34
+ end
40
35
 
41
- def shards
42
- shards = Set.new
36
+ def using_group(*groups)
37
+ return self unless connection.is_a?(Octopus::Proxy)
43
38
 
44
- if groups = (current_group_specified ? current_group : Octopus.config[:default_migration_group])
45
- Array.wrap(groups).each do |group|
46
- group_shards = connection.shards_for_group(group)
47
- shards.merge(group_shards) if group_shards
48
- end
49
- elsif shard = current_shard
50
- shards.merge(Array.wrap(shard))
39
+ self.current_group = groups
40
+ self.current_group_specified = true
41
+ self
51
42
  end
52
43
 
53
- shards.to_a.presence || [:master]
44
+ def shards
45
+ shards = Set.new
46
+
47
+ if (groups = (current_group_specified ? current_group : Octopus.config[:default_migration_group]))
48
+ Array.wrap(groups).each do |group|
49
+ group_shards = connection.shards_for_group(group)
50
+ shards.merge(group_shards) if group_shards
51
+ end
52
+ elsif (shard = current_shard)
53
+ shards.merge(Array.wrap(shard))
54
+ end
55
+
56
+ shards.to_a.presence || [Octopus.master_shard]
57
+ end
54
58
  end
55
59
  end
56
60
  end
57
61
 
58
- module Octopus::Migrator
59
- def self.included(base)
60
- base.extend(ClassMethods)
61
-
62
- base.class_eval do
63
- class << self
64
- alias_method_chain :migrate, :octopus
65
- alias_method_chain :up, :octopus
66
- alias_method_chain :down, :octopus
67
- alias_method_chain :run, :octopus
62
+ module Octopus
63
+ module Migrator
64
+ def self.included(base)
65
+ unless Octopus.atleast_rails52?
66
+ base.extend(ClassMethods)
67
+
68
+ base.class_eval do
69
+ class << self
70
+ alias_method :migrate_without_octopus, :migrate
71
+ alias_method :migrate, :migrate_with_octopus
72
+
73
+ alias_method :up_without_octopus, :up
74
+ alias_method :up, :up_with_octopus
75
+
76
+ alias_method :down_without_octopus, :down
77
+ alias_method :down, :down_with_octopus
78
+
79
+ alias_method :run_without_octopus, :run
80
+ alias_method :run, :run_with_octopus
81
+
82
+ alias_method :rollback_without_octopus, :rollback
83
+ alias_method :rollback, :rollback_with_octopus
84
+ end
85
+ end
68
86
  end
69
- end
70
87
 
71
- base.alias_method_chain :run, :octopus
72
- base.alias_method_chain :migrate, :octopus
73
- base.alias_method_chain :migrations, :octopus
74
- end
88
+ base.send :alias_method, :run_without_octopus, :run
89
+ base.send :alias_method, :run, :run_with_octopus
75
90
 
76
- def run_with_octopus(&block)
77
- run_without_octopus(&block)
78
- rescue ActiveRecord::UnknownMigrationVersionError => e
79
- raise unless migrations(true).find {|m| m.version == e.version}
80
- end
91
+ base.send :alias_method, :migrate_without_octopus, :migrate
92
+ base.send :alias_method, :migrate, :migrate_with_octopus
81
93
 
82
- def migrate_with_octopus(&block)
83
- migrate_without_octopus(&block)
84
- rescue ActiveRecord::UnknownMigrationVersionError => e
85
- raise unless migrations(true).find {|m| m.version == e.version}
86
- end
94
+ base.send :alias_method, :migrations_without_octopus, :migrations
95
+ base.send :alias_method, :migrations, :migrations_with_octopus
96
+ end
97
+ if Octopus.atleast_rails52?
98
+ ### Post RAILS 5.2 Migration methods
99
+
100
+ def run_with_octopus(&block)
101
+ return run_without_octopus(&block) unless connection.is_a?(Octopus::Proxy)
102
+ shards = migrations.map(&:shards).flatten.map(&:to_s)
103
+ connection.send_queries_to_multiple_shards(shards) do
104
+ run_without_octopus(&block)
105
+ end
106
+ rescue ActiveRecord::UnknownMigrationVersionError => e
107
+ raise unless migrations(true).detect { |m| m.version == e.version }
108
+ end
87
109
 
88
- def migrations_with_octopus(shard_agnostic = false)
89
- connection = ActiveRecord::Base.connection
90
- migrations = migrations_without_octopus
91
- return migrations if !connection.is_a?(Octopus::Proxy) || shard_agnostic
110
+ def migrate_with_octopus(&block)
111
+ return migrate_without_octopus(&block) unless connection.is_a?(Octopus::Proxy)
112
+ shards = migrations.map(&:shards).flatten.map(&:to_s)
113
+ connection.send_queries_to_multiple_shards(shards) do
114
+ migrate_without_octopus(&block)
115
+ end
116
+ rescue ActiveRecord::UnknownMigrationVersionError => e
117
+ raise unless migrations(true).detect { |m| m.version == e.version }
118
+ end
92
119
 
93
- migrations.select {|m| m.shards.include?(connection.current_shard.to_sym)}
94
- end
120
+ def migrations_with_octopus(shard_agnostic = true)
121
+ migrations = migrations_without_octopus
122
+ return migrations if !connection.is_a?(Octopus::Proxy) || shard_agnostic
95
123
 
96
- module ClassMethods
97
- def migrate_with_octopus(migrations_paths, target_version = nil, &block)
98
- return migrate_without_octopus(migrations_paths, target_version, &block) unless connection.is_a?(Octopus::Proxy)
124
+ migrations.select { |m| m.shards.include?(connection.current_shard.to_sym) }
125
+ end
126
+
127
+ private
128
+
129
+ def connection
130
+ ActiveRecord::Base.connection
131
+ end
132
+
133
+ else
134
+ ### Pre RAILS 5.2 Migration methods
135
+
136
+ def run_with_octopus(&block)
137
+ run_without_octopus(&block)
138
+ rescue ActiveRecord::UnknownMigrationVersionError => e
139
+ raise unless migrations(true).detect { |m| m.version == e.version }
140
+ end
99
141
 
100
- connection.send_queries_to_multiple_shards(connection.shard_names) do
101
- migrate_without_octopus(migrations_paths, target_version, &block)
142
+ def migrate_with_octopus(&block)
143
+ migrate_without_octopus(&block)
144
+ rescue ActiveRecord::UnknownMigrationVersionError => e
145
+ raise unless migrations(true).detect { |m| m.version == e.version }
102
146
  end
103
- end
104
147
 
105
- def up_with_octopus(migrations_paths, target_version = nil, &block)
106
- return up_without_octopus(migrations_paths, target_version, &block) unless connection.is_a?(Octopus::Proxy)
107
- return up_without_octopus(migrations_paths, target_version, &block) unless connection.current_shard == :master
148
+ def migrations_with_octopus(shard_agnostic = false)
149
+ connection = ActiveRecord::Base.connection
150
+ migrations = migrations_without_octopus
151
+ return migrations if !connection.is_a?(Octopus::Proxy) || shard_agnostic
108
152
 
109
- connection.send_queries_to_multiple_shards(connection.shard_names) do
110
- up_without_octopus(migrations_paths, target_version, &block)
153
+ migrations.select { |m| m.shards.include?(connection.current_shard.to_sym) }
111
154
  end
112
- end
113
155
 
114
- def down_with_octopus(migrations_paths, target_version = nil, &block)
115
- return down_without_octopus(migrations_paths, target_version, &block) unless connection.is_a?(Octopus::Proxy)
116
- return down_without_octopus(migrations_paths, target_version, &block) unless connection.current_shard == :master
156
+ module ClassMethods
157
+ def migrate_with_octopus(migrations_paths, target_version = nil, &block)
158
+ return migrate_without_octopus(migrations_paths, target_version, &block) unless connection.is_a?(Octopus::Proxy)
117
159
 
118
- connection.send_queries_to_multiple_shards(connection.shard_names) do
119
- down_without_octopus(migrations_paths, target_version, &block)
120
- end
121
- end
160
+ connection.send_queries_to_multiple_shards(connection.shard_names) do
161
+ migrate_without_octopus(migrations_paths, target_version, &block)
162
+ end
163
+ end
122
164
 
123
- def run_with_octopus(direction, migrations_paths, target_version)
124
- return run_without_octopus(direction, migrations_paths, target_version) unless connection.is_a?(Octopus::Proxy)
165
+ def up_with_octopus(migrations_paths, target_version = nil, &block)
166
+ return up_without_octopus(migrations_paths, target_version, &block) unless connection.is_a?(Octopus::Proxy)
167
+ return up_without_octopus(migrations_paths, target_version, &block) unless connection.current_shard.to_s == Octopus.master_shard.to_s
125
168
 
126
- connection.send_queries_to_multiple_shards(connection.shard_names) do
127
- run_without_octopus(direction, migrations_paths, target_version)
128
- end
129
- end
169
+ connection.send_queries_to_multiple_shards(connection.shard_names) do
170
+ up_without_octopus(migrations_paths, target_version, &block)
171
+ end
172
+ end
130
173
 
131
- private
132
- def connection
133
- ActiveRecord::Base.connection
174
+ def down_with_octopus(migrations_paths, target_version = nil, &block)
175
+ return down_without_octopus(migrations_paths, target_version, &block) unless connection.is_a?(Octopus::Proxy)
176
+ return down_without_octopus(migrations_paths, target_version, &block) unless connection.current_shard.to_s == Octopus.master_shard.to_s
177
+
178
+ connection.send_queries_to_multiple_shards(connection.shard_names) do
179
+ down_without_octopus(migrations_paths, target_version, &block)
180
+ end
181
+ end
182
+
183
+ def run_with_octopus(direction, migrations_paths, target_version)
184
+ return run_without_octopus(direction, migrations_paths, target_version) unless connection.is_a?(Octopus::Proxy)
185
+
186
+ connection.send_queries_to_multiple_shards(connection.shard_names) do
187
+ run_without_octopus(direction, migrations_paths, target_version)
188
+ end
189
+ end
190
+
191
+ def rollback_with_octopus(migrations_paths, steps = 1)
192
+ return rollback_without_octopus(migrations_paths, steps) unless connection.is_a?(Octopus::Proxy)
193
+
194
+ connection.send_queries_to_multiple_shards(connection.shard_names) do
195
+ rollback_without_octopus(migrations_paths, steps)
196
+ end
197
+ end
198
+
199
+ private
200
+
201
+ def connection
202
+ ActiveRecord::Base.connection
203
+ end
204
+ end
134
205
  end
135
206
  end
136
207
  end
137
208
 
138
- module Octopus::MigrationProxy
139
- def shards
140
- migration.class.shards
209
+ module Octopus
210
+ module MigrationProxy
211
+ def shards
212
+ migration.class.shards
213
+ end
141
214
  end
142
215
  end
143
216
 
144
- module Octopus::UnknownMigrationVersionError
145
- def self.included(base)
146
- base.alias_method_chain :initialize, :octopus
147
- base.send(:attr_accessor, :version)
148
- end
217
+ module Octopus
218
+ module UnknownMigrationVersionError
219
+ def self.included(base)
220
+ base.send :alias_method, :initialize_without_octopus, :initialize
221
+ base.send :alias_method, :initialize, :initialize_with_octopus
149
222
 
150
- def initialize_with_octopus(version)
151
- @version = version
152
- initialize_without_octopus(version)
223
+ base.send(:attr_accessor, :version)
224
+ end
225
+
226
+ def initialize_with_octopus(version)
227
+ @version = version
228
+ initialize_without_octopus(version)
229
+ end
153
230
  end
154
231
  end
155
232