rubyrep 1.0.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/History.txt +4 -0
- data/License.txt +20 -0
- data/Manifest.txt +137 -0
- data/README.txt +37 -0
- data/Rakefile +30 -0
- data/bin/rubyrep +8 -0
- data/config/hoe.rb +72 -0
- data/config/mysql_config.rb +25 -0
- data/config/postgres_config.rb +21 -0
- data/config/proxied_test_config.rb +14 -0
- data/config/redmine_config.rb +17 -0
- data/config/rep_config.rb +20 -0
- data/config/requirements.rb +32 -0
- data/config/test_config.rb +20 -0
- data/lib/rubyrep/base_runner.rb +195 -0
- data/lib/rubyrep/command_runner.rb +144 -0
- data/lib/rubyrep/committers/buffered_committer.rb +140 -0
- data/lib/rubyrep/committers/committers.rb +146 -0
- data/lib/rubyrep/configuration.rb +240 -0
- data/lib/rubyrep/connection_extenders/connection_extenders.rb +133 -0
- data/lib/rubyrep/connection_extenders/jdbc_extender.rb +284 -0
- data/lib/rubyrep/connection_extenders/mysql_extender.rb +168 -0
- data/lib/rubyrep/connection_extenders/postgresql_extender.rb +261 -0
- data/lib/rubyrep/database_proxy.rb +52 -0
- data/lib/rubyrep/direct_table_scan.rb +75 -0
- data/lib/rubyrep/generate_runner.rb +105 -0
- data/lib/rubyrep/initializer.rb +39 -0
- data/lib/rubyrep/logged_change.rb +326 -0
- data/lib/rubyrep/proxied_table_scan.rb +171 -0
- data/lib/rubyrep/proxy_block_cursor.rb +145 -0
- data/lib/rubyrep/proxy_connection.rb +318 -0
- data/lib/rubyrep/proxy_cursor.rb +44 -0
- data/lib/rubyrep/proxy_row_cursor.rb +43 -0
- data/lib/rubyrep/proxy_runner.rb +89 -0
- data/lib/rubyrep/replication_difference.rb +91 -0
- data/lib/rubyrep/replication_extenders/mysql_replication.rb +271 -0
- data/lib/rubyrep/replication_extenders/postgresql_replication.rb +204 -0
- data/lib/rubyrep/replication_extenders/replication_extenders.rb +26 -0
- data/lib/rubyrep/replication_helper.rb +104 -0
- data/lib/rubyrep/replication_initializer.rb +307 -0
- data/lib/rubyrep/replication_run.rb +48 -0
- data/lib/rubyrep/replication_runner.rb +138 -0
- data/lib/rubyrep/replicators/replicators.rb +37 -0
- data/lib/rubyrep/replicators/two_way_replicator.rb +334 -0
- data/lib/rubyrep/scan_progress_printers/progress_bar.rb +65 -0
- data/lib/rubyrep/scan_progress_printers/scan_progress_printers.rb +65 -0
- data/lib/rubyrep/scan_report_printers/scan_detail_reporter.rb +111 -0
- data/lib/rubyrep/scan_report_printers/scan_report_printers.rb +67 -0
- data/lib/rubyrep/scan_report_printers/scan_summary_reporter.rb +75 -0
- data/lib/rubyrep/scan_runner.rb +25 -0
- data/lib/rubyrep/session.rb +177 -0
- data/lib/rubyrep/sync_helper.rb +111 -0
- data/lib/rubyrep/sync_runner.rb +31 -0
- data/lib/rubyrep/syncers/syncers.rb +112 -0
- data/lib/rubyrep/syncers/two_way_syncer.rb +174 -0
- data/lib/rubyrep/table_scan.rb +54 -0
- data/lib/rubyrep/table_scan_helper.rb +38 -0
- data/lib/rubyrep/table_sorter.rb +70 -0
- data/lib/rubyrep/table_spec_resolver.rb +136 -0
- data/lib/rubyrep/table_sync.rb +68 -0
- data/lib/rubyrep/trigger_mode_switcher.rb +63 -0
- data/lib/rubyrep/type_casting_cursor.rb +31 -0
- data/lib/rubyrep/uninstall_runner.rb +92 -0
- data/lib/rubyrep/version.rb +9 -0
- data/lib/rubyrep.rb +68 -0
- data/script/destroy +14 -0
- data/script/generate +14 -0
- data/script/txt2html +74 -0
- data/setup.rb +1585 -0
- data/sims/performance/big_rep_spec.rb +100 -0
- data/sims/performance/big_scan_spec.rb +57 -0
- data/sims/performance/big_sync_spec.rb +141 -0
- data/sims/performance/performance.rake +228 -0
- data/sims/sim_helper.rb +24 -0
- data/spec/base_runner_spec.rb +218 -0
- data/spec/buffered_committer_spec.rb +271 -0
- data/spec/command_runner_spec.rb +145 -0
- data/spec/committers_spec.rb +174 -0
- data/spec/configuration_spec.rb +198 -0
- data/spec/connection_extender_interface_spec.rb +138 -0
- data/spec/connection_extenders_registration_spec.rb +129 -0
- data/spec/database_proxy_spec.rb +48 -0
- data/spec/database_rake_spec.rb +40 -0
- data/spec/db_specific_connection_extenders_spec.rb +34 -0
- data/spec/db_specific_replication_extenders_spec.rb +38 -0
- data/spec/direct_table_scan_spec.rb +61 -0
- data/spec/generate_runner_spec.rb +84 -0
- data/spec/initializer_spec.rb +46 -0
- data/spec/logged_change_spec.rb +480 -0
- data/spec/postgresql_replication_spec.rb +48 -0
- data/spec/postgresql_support_spec.rb +57 -0
- data/spec/progress_bar_spec.rb +77 -0
- data/spec/proxied_table_scan_spec.rb +151 -0
- data/spec/proxy_block_cursor_spec.rb +197 -0
- data/spec/proxy_connection_spec.rb +399 -0
- data/spec/proxy_cursor_spec.rb +56 -0
- data/spec/proxy_row_cursor_spec.rb +66 -0
- data/spec/proxy_runner_spec.rb +70 -0
- data/spec/replication_difference_spec.rb +160 -0
- data/spec/replication_extender_interface_spec.rb +365 -0
- data/spec/replication_extenders_spec.rb +32 -0
- data/spec/replication_helper_spec.rb +121 -0
- data/spec/replication_initializer_spec.rb +477 -0
- data/spec/replication_run_spec.rb +166 -0
- data/spec/replication_runner_spec.rb +213 -0
- data/spec/replicators_spec.rb +31 -0
- data/spec/rubyrep_spec.rb +8 -0
- data/spec/scan_detail_reporter_spec.rb +119 -0
- data/spec/scan_progress_printers_spec.rb +68 -0
- data/spec/scan_report_printers_spec.rb +67 -0
- data/spec/scan_runner_spec.rb +50 -0
- data/spec/scan_summary_reporter_spec.rb +61 -0
- data/spec/session_spec.rb +212 -0
- data/spec/spec.opts +1 -0
- data/spec/spec_helper.rb +295 -0
- data/spec/sync_helper_spec.rb +157 -0
- data/spec/sync_runner_spec.rb +78 -0
- data/spec/syncers_spec.rb +171 -0
- data/spec/table_scan_helper_spec.rb +29 -0
- data/spec/table_scan_spec.rb +49 -0
- data/spec/table_sorter_spec.rb +31 -0
- data/spec/table_spec_resolver_spec.rb +102 -0
- data/spec/table_sync_spec.rb +84 -0
- data/spec/trigger_mode_switcher_spec.rb +83 -0
- data/spec/two_way_replicator_spec.rb +551 -0
- data/spec/two_way_syncer_spec.rb +256 -0
- data/spec/type_casting_cursor_spec.rb +50 -0
- data/spec/uninstall_runner_spec.rb +86 -0
- data/tasks/database.rake +439 -0
- data/tasks/deployment.rake +29 -0
- data/tasks/environment.rake +9 -0
- data/tasks/java.rake +37 -0
- data/tasks/redmine_test.rake +47 -0
- data/tasks/rspec.rake +68 -0
- data/tasks/rubyrep.tailor +18 -0
- data/tasks/stats.rake +19 -0
- data/tasks/task_helper.rb +20 -0
- data.tar.gz.sig +0 -0
- metadata +243 -0
- metadata.gz.sig +0 -0
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
require 'benchmark'
|
|
2
|
+
|
|
3
|
+
require File.dirname(__FILE__) + '/../../spec/spec_helper.rb'
|
|
4
|
+
require File.dirname(__FILE__) + '/../sim_helper'
|
|
5
|
+
|
|
6
|
+
include RR
|
|
7
|
+
|
|
8
|
+
describe "Big Rep" do
|
|
9
|
+
before(:each) do
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
# Calculates and returns the number of records of the specified table.
|
|
13
|
+
# * +session+ current Session instance
|
|
14
|
+
# * +database+: designates database, either :left or :right
|
|
15
|
+
# * +table+: name of the table
|
|
16
|
+
def record_quantity(session, database, table = 'big_rep')
|
|
17
|
+
session.send(database).select_one( \
|
|
18
|
+
"select count(id) as count from #{table}")['count'].to_i
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# Calculates and returns the sum of the number fields of records.
|
|
22
|
+
# * +session+: current Session instance
|
|
23
|
+
# * +database+: designates database, either :left or :right
|
|
24
|
+
def record_sum(session, database)
|
|
25
|
+
session.send(database).select_one( \
|
|
26
|
+
"select sum(number1) + sum(number2) + sum(number3) + sum(number4) as sum
|
|
27
|
+
from big_rep")['sum'].to_f
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# Returns the number of changes that remain to be replicated
|
|
31
|
+
# * +session+: current Session instance
|
|
32
|
+
def number_changes(session)
|
|
33
|
+
record_quantity(session, :left, 'rr_pending_changes') +
|
|
34
|
+
record_quantity(session, :right, 'rr_pending_changes')
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# Runs a replication of the big_rep table.
|
|
38
|
+
def run_rep
|
|
39
|
+
config = deep_copy(Initializer.configuration)
|
|
40
|
+
config.options = {
|
|
41
|
+
:committer => :buffered_commit,
|
|
42
|
+
:replication_conflict_handling => :later_wins,
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
session = Session.new config
|
|
46
|
+
initializer = ReplicationInitializer.new session
|
|
47
|
+
begin
|
|
48
|
+
[:left, :right].each do |database|
|
|
49
|
+
session.send(database).execute "insert into big_rep select * from big_rep_backup"
|
|
50
|
+
session.send(database).execute "insert into rr_pending_changes select * from big_rep_pending_changes"
|
|
51
|
+
initializer.create_trigger database, 'big_rep'
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
puts "\nReplicating (#{session.proxied? ? :proxied : :direct}) table big_rep (#{number_changes(session)} changes)"
|
|
55
|
+
|
|
56
|
+
t = Thread.new do
|
|
57
|
+
remaining_changes = number_changes(session)
|
|
58
|
+
progress_bar = ScanProgressPrinters::ProgressBar.new(remaining_changes, session, 'big_rep', 'big_rep')
|
|
59
|
+
while remaining_changes > 0
|
|
60
|
+
sleep 1
|
|
61
|
+
new_remaining_changes = number_changes(session)
|
|
62
|
+
progress_bar.step remaining_changes - new_remaining_changes
|
|
63
|
+
remaining_changes = new_remaining_changes
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
run = ReplicationRun.new session
|
|
68
|
+
benchmark = Benchmark.measure { run.run }
|
|
69
|
+
t.join 10
|
|
70
|
+
puts "\n time required: #{benchmark}"
|
|
71
|
+
|
|
72
|
+
left_fingerprint = {
|
|
73
|
+
:quantity => record_quantity(session, :left),
|
|
74
|
+
:sum => record_sum(session, :left)
|
|
75
|
+
}
|
|
76
|
+
right_fingerprint = {
|
|
77
|
+
:quantity => record_quantity(session, :right),
|
|
78
|
+
:sum => record_sum(session, :right)
|
|
79
|
+
}
|
|
80
|
+
left_fingerprint.should == right_fingerprint
|
|
81
|
+
ensure
|
|
82
|
+
[:left, :right].each do |database|
|
|
83
|
+
initializer.drop_trigger database, 'big_rep'
|
|
84
|
+
session.send(database).execute "delete from big_rep"
|
|
85
|
+
session.send(database).execute "delete from rr_pending_changes"
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
it "Direct Replication should replicate correctly" do
|
|
91
|
+
Initializer.configuration = standard_config
|
|
92
|
+
run_rep
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
it "Proxied Replication should replicate correctly" do
|
|
96
|
+
ensure_proxy
|
|
97
|
+
Initializer.configuration = proxied_config
|
|
98
|
+
run_rep
|
|
99
|
+
end
|
|
100
|
+
end
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
require 'benchmark'
|
|
2
|
+
|
|
3
|
+
require File.dirname(__FILE__) + '/../../spec/spec_helper.rb'
|
|
4
|
+
require File.dirname(__FILE__) + '/../sim_helper'
|
|
5
|
+
|
|
6
|
+
include RR
|
|
7
|
+
|
|
8
|
+
describe "Big Scan" do
|
|
9
|
+
before(:each) do
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
# Runs a scan of the big_scan table
|
|
13
|
+
def run_scan
|
|
14
|
+
session = Session.new
|
|
15
|
+
expected_result = {}
|
|
16
|
+
expected_result[:conflict] = session.left.select_one( \
|
|
17
|
+
"select count(id) as count from big_scan where diff_type = 'conflict'")['count'].to_i
|
|
18
|
+
expected_result[:left] = session.left.select_one( \
|
|
19
|
+
"select count(id) as count from big_scan where diff_type = 'left'")['count'].to_i
|
|
20
|
+
expected_result[:right] = session.right.select_one( \
|
|
21
|
+
"select count(id) as count from big_scan where diff_type = 'right'")['count'].to_i
|
|
22
|
+
|
|
23
|
+
number_records = session.left.select_one( \
|
|
24
|
+
"select count(id) as count from big_scan")['count'].to_i \
|
|
25
|
+
+ expected_result[:right]
|
|
26
|
+
number_differences = expected_result.values.inject {|sum, n| sum + n }
|
|
27
|
+
received_result = {:conflict => 0, :left => 0, :right => 0}
|
|
28
|
+
|
|
29
|
+
table_scan_class = TableScanHelper.scan_class(session)
|
|
30
|
+
puts "\nScanning table big_scan (#{number_differences} differences in #{number_records} records) using #{table_scan_class.name}"
|
|
31
|
+
|
|
32
|
+
scan = table_scan_class.new session, 'big_scan'
|
|
33
|
+
scan.progress_printer = RR::ScanProgressPrinters::ProgressBar
|
|
34
|
+
benchmark = Benchmark.measure {
|
|
35
|
+
scan.run do |diff_type, row|
|
|
36
|
+
received_result[diff_type] += 1
|
|
37
|
+
end
|
|
38
|
+
}
|
|
39
|
+
puts "\n time required: #{benchmark}"
|
|
40
|
+
|
|
41
|
+
received_result.should == expected_result
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
it "ProxiedTableScan should identify differences between big_scan tables correctly" do
|
|
45
|
+
Initializer.configuration = deep_copy(proxied_config)
|
|
46
|
+
Initializer.configuration.options[:proxy_block_size] = 100
|
|
47
|
+
ensure_proxy
|
|
48
|
+
|
|
49
|
+
run_scan
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
it "DirectTableScan should identify differences between big_scan tables correctly" do
|
|
53
|
+
Initializer.configuration = standard_config
|
|
54
|
+
|
|
55
|
+
run_scan
|
|
56
|
+
end
|
|
57
|
+
end
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
require 'benchmark'
|
|
2
|
+
|
|
3
|
+
require File.dirname(__FILE__) + '/../../spec/spec_helper.rb'
|
|
4
|
+
require File.dirname(__FILE__) + '/../sim_helper'
|
|
5
|
+
|
|
6
|
+
include RR
|
|
7
|
+
|
|
8
|
+
describe "Big Sync" do
|
|
9
|
+
before(:each) do
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
# Calculates and returns number of records of a given type.
|
|
13
|
+
# * :session: current Session instance
|
|
14
|
+
# * :record_type: type of records (String)
|
|
15
|
+
# * :database: designates database, either :left or :right
|
|
16
|
+
def record_quantity(session, record_type, database)
|
|
17
|
+
session.send(database).select_one( \
|
|
18
|
+
"select count(id) as count from big_scan where diff_type = '#{record_type}'")['count'].to_i
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# Calculates and returns the sum of the number fields of records of the given type.
|
|
22
|
+
# * :session: current Session instance
|
|
23
|
+
# * :record_type: type of records (:left, :right, :same or :conflict)
|
|
24
|
+
# * :database: designates database, either :left or :right
|
|
25
|
+
def record_sum(session, record_type, database)
|
|
26
|
+
session.send(database).select_one( \
|
|
27
|
+
"select sum(number1) + sum(number2) + sum(number3) + sum(number4) as sum
|
|
28
|
+
from big_scan where diff_type = '#{record_type}'")['sum'].to_f
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# Runs a sync of the big_scan table.
|
|
32
|
+
# * session: the current Session
|
|
33
|
+
# * expected_result: a hash of record quantities that should result.
|
|
34
|
+
def run_sync(session, expected_result)
|
|
35
|
+
begin
|
|
36
|
+
number_records =
|
|
37
|
+
record_quantity(session, :left, :left) +
|
|
38
|
+
record_quantity(session, :conflict, :left) +
|
|
39
|
+
record_quantity(session, :same, :left) +
|
|
40
|
+
record_quantity(session, :right, :right)
|
|
41
|
+
|
|
42
|
+
number_differences =
|
|
43
|
+
record_quantity(session, :left, :left) +
|
|
44
|
+
record_quantity(session, :conflict, :left) +
|
|
45
|
+
record_quantity(session, :right, :right)
|
|
46
|
+
|
|
47
|
+
puts "\nSyncing (#{Initializer.configuration.options[:syncer]}, #{session.proxied? ? :proxied : :direct}) table big_scan (#{number_differences} differences in #{number_records} records)"
|
|
48
|
+
|
|
49
|
+
sync = TableSync.new(session, 'big_scan')
|
|
50
|
+
sync.progress_printer = RR::ScanProgressPrinters::ProgressBar
|
|
51
|
+
benchmark = Benchmark.measure { sync.run { |diff_type, row| } }
|
|
52
|
+
puts "\n time required: #{benchmark}"
|
|
53
|
+
|
|
54
|
+
{
|
|
55
|
+
:conflict_on_left => record_quantity(session, :conflict, :left),
|
|
56
|
+
:conflict_on_right => record_quantity(session, :conflict, :right),
|
|
57
|
+
:conflict_sum_on_left => record_sum(session, :conflict, :left),
|
|
58
|
+
:conflict_sum_on_right => record_sum(session, :conflict, :right),
|
|
59
|
+
:left_on_left => record_quantity(session, :left, :left),
|
|
60
|
+
:left_on_right => record_quantity(session, :left, :right),
|
|
61
|
+
:right_on_left => record_quantity(session, :right, :left),
|
|
62
|
+
:right_on_right => record_quantity(session, :right, :right)
|
|
63
|
+
}.should == expected_result
|
|
64
|
+
ensure
|
|
65
|
+
Committers::NeverCommitter.rollback_current_session
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
it "Proxied OneWaySync should sync correctly" do
|
|
70
|
+
ensure_proxy
|
|
71
|
+
Initializer.configuration = deep_copy(proxied_config)
|
|
72
|
+
|
|
73
|
+
Initializer.configuration.options = {
|
|
74
|
+
:committer => :never_commit,
|
|
75
|
+
:syncer => :one_way,
|
|
76
|
+
:direction => :right,
|
|
77
|
+
:delete => true,
|
|
78
|
+
:proxy_block_size => 100,
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
session = Session.new
|
|
82
|
+
expected_result = {
|
|
83
|
+
:conflict_on_left => record_quantity(session, :conflict, :left),
|
|
84
|
+
:conflict_on_right => record_quantity(session, :conflict, :right),
|
|
85
|
+
:conflict_sum_on_left => record_sum(session, :conflict, :left),
|
|
86
|
+
:conflict_sum_on_right => record_sum(session, :conflict, :left),
|
|
87
|
+
:left_on_left => record_quantity(session, :left, :left),
|
|
88
|
+
:left_on_right => record_quantity(session, :left, :left),
|
|
89
|
+
:right_on_left => 0,
|
|
90
|
+
:right_on_right => 0
|
|
91
|
+
}
|
|
92
|
+
run_sync session, expected_result
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
it "Direct OneWaySync should sync correctly" do
|
|
96
|
+
Initializer.configuration = deep_copy(standard_config)
|
|
97
|
+
Initializer.configuration.options = {
|
|
98
|
+
:committer => :never_commit,
|
|
99
|
+
:syncer => :one_way,
|
|
100
|
+
:direction => :right,
|
|
101
|
+
:delete => true
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
session = Session.new
|
|
105
|
+
expected_result = {
|
|
106
|
+
:conflict_on_left => record_quantity(session, :conflict, :left),
|
|
107
|
+
:conflict_on_right => record_quantity(session, :conflict, :right),
|
|
108
|
+
:conflict_sum_on_left => record_sum(session, :conflict, :left),
|
|
109
|
+
:conflict_sum_on_right => record_sum(session, :conflict, :left),
|
|
110
|
+
:left_on_left => record_quantity(session, :left, :left),
|
|
111
|
+
:left_on_right => record_quantity(session, :left, :left),
|
|
112
|
+
:right_on_left => 0,
|
|
113
|
+
:right_on_right => 0
|
|
114
|
+
}
|
|
115
|
+
run_sync session, expected_result
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
it "Proxied TwoWaySync should sync correctly" do
|
|
119
|
+
ensure_proxy
|
|
120
|
+
Initializer.configuration = deep_copy(proxied_config)
|
|
121
|
+
Initializer.configuration.options = {
|
|
122
|
+
:committer => :never_commit,
|
|
123
|
+
:syncer => :two_way,
|
|
124
|
+
:sync_conflict_handling => :right_wins,
|
|
125
|
+
:proxy_block_size => 100,
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
session = Session.new
|
|
129
|
+
expected_result = {
|
|
130
|
+
:conflict_on_left => record_quantity(session, :conflict, :left),
|
|
131
|
+
:conflict_on_right => record_quantity(session, :conflict, :right),
|
|
132
|
+
:conflict_sum_on_left => record_sum(session, :conflict, :right),
|
|
133
|
+
:conflict_sum_on_right => record_sum(session, :conflict, :right),
|
|
134
|
+
:left_on_left => record_quantity(session, :left, :left),
|
|
135
|
+
:left_on_right => record_quantity(session, :left, :left),
|
|
136
|
+
:right_on_left => record_quantity(session, :right, :right),
|
|
137
|
+
:right_on_right => record_quantity(session, :right, :right)
|
|
138
|
+
}
|
|
139
|
+
run_sync session, expected_result
|
|
140
|
+
end
|
|
141
|
+
end
|
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
require 'rake'
|
|
2
|
+
require 'benchmark'
|
|
3
|
+
|
|
4
|
+
require File.dirname(__FILE__) + '/../sim_helper'
|
|
5
|
+
|
|
6
|
+
# Prepares the database schema for the performance tests.
|
|
7
|
+
def prepare_schema
|
|
8
|
+
session = RR::Session.new
|
|
9
|
+
|
|
10
|
+
[:left, :right].each do |database|
|
|
11
|
+
[:big_scan, :big_rep, :big_rep_backup].each do |table|
|
|
12
|
+
session.send(database).drop_table table rescue nil
|
|
13
|
+
session.send(database).create_table table do |t|
|
|
14
|
+
t.column :diff_type, :string
|
|
15
|
+
t.string :text1, :text2, :text3, :text4
|
|
16
|
+
t.text :text5
|
|
17
|
+
t.binary :text6
|
|
18
|
+
t.integer :number1, :number2, :number3
|
|
19
|
+
t.float :number4
|
|
20
|
+
end rescue nil
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
BIG_SCAN_RECORD_NUMBER = 5000 # number of records to create for simulation
|
|
26
|
+
BIG_SCAN_SEED = 123 # random number seed to make simulation repeatable
|
|
27
|
+
|
|
28
|
+
# Percentage values for same, modified, left_only and right_only records in simulation
|
|
29
|
+
BIG_SCAN_SAME = 95
|
|
30
|
+
BIG_SCAN_MODIFIED = BIG_SCAN_SAME + 3
|
|
31
|
+
BIG_SCAN_LEFT_ONLY = BIG_SCAN_MODIFIED + 1 # difference to 100% will be right_only records
|
|
32
|
+
|
|
33
|
+
def big_scan_columns
|
|
34
|
+
@@big_scan_columns ||= nil
|
|
35
|
+
unless @@big_scan_columns
|
|
36
|
+
session = RR::Session.new
|
|
37
|
+
@@big_scan_columns = session.left.column_names('big_scan')
|
|
38
|
+
end
|
|
39
|
+
@@big_scan_columns
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def text_columns
|
|
43
|
+
@@text_columns ||= big_scan_columns.select {|column_name| column_name =~ /^text/}
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def number_columns
|
|
47
|
+
@@number_columns ||= big_scan_columns.select {|column_name| column_name =~ /^number/}
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def random_attributes
|
|
51
|
+
attributes = {}
|
|
52
|
+
text_columns.each {|column_name| attributes[column_name] = "text#{rand(1000)}"}
|
|
53
|
+
number_columns.each {|column_name| attributes[column_name] = rand(1000)}
|
|
54
|
+
attributes
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
# Populates the big_scan tables with sample data.
|
|
58
|
+
def populate_scan_data()
|
|
59
|
+
session = RR::Session.new
|
|
60
|
+
|
|
61
|
+
[:left, :right].each {|database| session.send(database).execute "delete from big_scan"}
|
|
62
|
+
|
|
63
|
+
srand BIG_SCAN_SEED
|
|
64
|
+
|
|
65
|
+
puts "\nGenerating #{BIG_SCAN_RECORD_NUMBER} records in big_scan"
|
|
66
|
+
progress_bar = ProgressBar.new BIG_SCAN_RECORD_NUMBER
|
|
67
|
+
|
|
68
|
+
(1..BIG_SCAN_RECORD_NUMBER).each do |i|
|
|
69
|
+
|
|
70
|
+
# Updating progress bar
|
|
71
|
+
progress_bar.step
|
|
72
|
+
|
|
73
|
+
attributes = random_attributes
|
|
74
|
+
attributes['id'] = i
|
|
75
|
+
|
|
76
|
+
case rand(100)
|
|
77
|
+
when 0...BIG_SCAN_SAME
|
|
78
|
+
attributes['diff_type'] = 'same'
|
|
79
|
+
[:left, :right].each {|database| session.send(database).insert_record 'big_scan', attributes}
|
|
80
|
+
when BIG_SCAN_SAME...BIG_SCAN_MODIFIED
|
|
81
|
+
attributes['diff_type'] = 'conflict'
|
|
82
|
+
session.left.insert_record 'big_scan', attributes
|
|
83
|
+
|
|
84
|
+
attribute_name = text_columns[rand(text_columns.size)]
|
|
85
|
+
attributes[attribute_name] = attributes[attribute_name] + 'modified'
|
|
86
|
+
attribute_name = number_columns[rand(number_columns.size)]
|
|
87
|
+
attributes[attribute_name] = attributes[attribute_name] + 10000
|
|
88
|
+
session.right.insert_record 'big_scan', attributes
|
|
89
|
+
when BIG_SCAN_MODIFIED...BIG_SCAN_LEFT_ONLY
|
|
90
|
+
attributes['diff_type'] = 'left'
|
|
91
|
+
session.left.insert_record 'big_scan', attributes
|
|
92
|
+
else
|
|
93
|
+
attributes['diff_type'] = 'right'
|
|
94
|
+
session.right.insert_record 'big_scan', attributes
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
BIG_REP_CHANGE_NUMBER = 5000 # number of records to create for simulation
|
|
100
|
+
BIG_REP_SEED = 456 # random number seed to make simulation repeatable
|
|
101
|
+
|
|
102
|
+
# Percentage values for inserts, updates and deletes in simulation
|
|
103
|
+
BIG_REP_INSERT = 45
|
|
104
|
+
BIG_REP_UPDATE = BIG_REP_INSERT + 30 # different to 100% will be deletes
|
|
105
|
+
|
|
106
|
+
# Populates the big_rep tables with sample data and changes.
|
|
107
|
+
def populate_rep_data
|
|
108
|
+
session = RR::Session.new
|
|
109
|
+
initializer = RR::ReplicationInitializer.new session
|
|
110
|
+
|
|
111
|
+
# step 1: clear change log; ensure trigger, initialize big_rep table from data in big_scan
|
|
112
|
+
[:left, :right].each do |database|
|
|
113
|
+
initializer.drop_trigger(database, 'big_rep') rescue nil
|
|
114
|
+
session.send(database).execute "delete from big_rep"
|
|
115
|
+
session.send(database).execute "insert into big_rep select * from big_scan where diff_type = 'same'"
|
|
116
|
+
session.send(database).execute "delete from rr_pending_changes"
|
|
117
|
+
initializer.create_trigger(database, 'big_rep')
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
# step 2: generate changes
|
|
121
|
+
|
|
122
|
+
srand BIG_REP_SEED
|
|
123
|
+
|
|
124
|
+
# Keep tracks of the record ids in each database
|
|
125
|
+
all_ids = {}
|
|
126
|
+
all_ids[:left] = session.left.select_all("select id from big_rep").map {|row| row['id']}
|
|
127
|
+
all_ids[:right] = all_ids[:left].clone
|
|
128
|
+
|
|
129
|
+
# Next available id value
|
|
130
|
+
next_id = session.left.select_one("select max(id) + 1 as id from big_rep")['id'].to_i
|
|
131
|
+
|
|
132
|
+
puts "\nGenerating #{BIG_REP_CHANGE_NUMBER} changes in big_rep"
|
|
133
|
+
progress_bar = ProgressBar.new BIG_REP_CHANGE_NUMBER
|
|
134
|
+
(1..BIG_REP_CHANGE_NUMBER).each do
|
|
135
|
+
|
|
136
|
+
# Updating progress bar
|
|
137
|
+
progress_bar.step
|
|
138
|
+
|
|
139
|
+
database = [:left, :right].rand
|
|
140
|
+
|
|
141
|
+
case rand(100)
|
|
142
|
+
when 0...BIG_REP_INSERT
|
|
143
|
+
attributes = random_attributes
|
|
144
|
+
attributes['diff_type'] = 'insert'
|
|
145
|
+
attributes['id'] = next_id
|
|
146
|
+
all_ids[database] << next_id
|
|
147
|
+
next_id += 1
|
|
148
|
+
session.send(database).insert_record 'big_rep', attributes
|
|
149
|
+
when BIG_REP_INSERT...BIG_REP_UPDATE
|
|
150
|
+
id = all_ids[database].rand
|
|
151
|
+
attributes = session.send(database).select_one("select * from big_rep where id = '#{id}'")
|
|
152
|
+
column = number_columns[rand(number_columns.size)]
|
|
153
|
+
attributes[column] = rand(1000)
|
|
154
|
+
session.send(database).update_record 'big_rep', attributes
|
|
155
|
+
else
|
|
156
|
+
i = rand(all_ids[database].size)
|
|
157
|
+
id = all_ids[database].delete_at(i)
|
|
158
|
+
session.send(database).delete_record 'big_rep', 'id' => id
|
|
159
|
+
end
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
# step 3: move data into backup tables
|
|
163
|
+
[:left, :right].each do |database|
|
|
164
|
+
session.send(database).execute "delete from big_rep_backup"
|
|
165
|
+
session.send(database).execute "insert into big_rep_backup select * from big_rep"
|
|
166
|
+
session.send(database).drop_table "big_rep_pending_changes" rescue nil
|
|
167
|
+
session.send(database).execute "create table big_rep_pending_changes as select * from rr_pending_changes"
|
|
168
|
+
initializer.drop_trigger database, 'big_rep'
|
|
169
|
+
session.send(database).execute "delete from big_rep"
|
|
170
|
+
session.send(database).execute "delete from rr_pending_changes"
|
|
171
|
+
end
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
# Generates the sample data
|
|
175
|
+
def populate_data
|
|
176
|
+
populate_scan_data
|
|
177
|
+
populate_rep_data
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
# Prepares the database for the performance simulations
|
|
181
|
+
def prepare
|
|
182
|
+
prepare_schema
|
|
183
|
+
puts "time required: " + Benchmark.measure {populate_data}.to_s
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
namespace :sims do
|
|
187
|
+
namespace :performance do
|
|
188
|
+
desc "Prepare database"
|
|
189
|
+
task :prepare do
|
|
190
|
+
prepare
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
desc "Runs the big_scan simulation"
|
|
194
|
+
task :scan do
|
|
195
|
+
Spec::Runner::CommandLine.run(
|
|
196
|
+
Spec::Runner::OptionParser.parse(
|
|
197
|
+
['--options', "spec/spec.opts", "./sims/performance/big_scan_spec.rb"],
|
|
198
|
+
$stdout, $stderr))
|
|
199
|
+
end
|
|
200
|
+
|
|
201
|
+
desc "Runs the big_sync simulation"
|
|
202
|
+
task :sync do
|
|
203
|
+
Spec::Runner::CommandLine.run(
|
|
204
|
+
Spec::Runner::OptionParser.parse(
|
|
205
|
+
['--options', "spec/spec.opts", "./sims/performance/big_sync_spec.rb"],
|
|
206
|
+
$stdout, $stderr))
|
|
207
|
+
end
|
|
208
|
+
|
|
209
|
+
desc "Runs the big_rep simulation"
|
|
210
|
+
task :rep do
|
|
211
|
+
Spec::Runner::CommandLine.run(
|
|
212
|
+
Spec::Runner::OptionParser.parse(
|
|
213
|
+
['--options', "spec/spec.opts", "./sims/performance/big_rep_spec.rb"],
|
|
214
|
+
$stdout, $stderr))
|
|
215
|
+
end
|
|
216
|
+
|
|
217
|
+
begin
|
|
218
|
+
require 'ruby-prof/task'
|
|
219
|
+
RubyProf::ProfileTask.new do |t|
|
|
220
|
+
t.test_files = FileList["./sims/performance/*_spec.rb"]
|
|
221
|
+
t.output_dir = 'profile'
|
|
222
|
+
t.printer = :flat
|
|
223
|
+
t.min_percent = 1
|
|
224
|
+
end
|
|
225
|
+
rescue LoadError
|
|
226
|
+
end
|
|
227
|
+
end
|
|
228
|
+
end
|
data/sims/sim_helper.rb
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# A helper class to print a text progress bar.
|
|
2
|
+
class ProgressBar
|
|
3
|
+
# Creates a new progress bar for a task consisting of +max+ steps.
|
|
4
|
+
# At 100% the progress bar will be +bar_length+ characters wide.
|
|
5
|
+
def initialize(max_steps, bar_length = 40)
|
|
6
|
+
@max_steps, @bar_length, @current_progress = max_steps, bar_length, 0
|
|
7
|
+
@steps_per_progress_bar_marker = @max_steps.to_f / @bar_length
|
|
8
|
+
@marker_counter = 0
|
|
9
|
+
puts "0%>#{'-' * (@bar_length - '0%>'.length - '100%>'.length)}>100%"
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
# Increases progress by +number_steps+ steps.
|
|
13
|
+
# If no argument provided, increase progress by 1 step.
|
|
14
|
+
def step(number_steps = 1)
|
|
15
|
+
@current_progress+= number_steps
|
|
16
|
+
if ((@current_progress - number_steps) / @steps_per_progress_bar_marker).to_i \
|
|
17
|
+
< (@current_progress / @steps_per_progress_bar_marker).to_i
|
|
18
|
+
@marker_counter += 1
|
|
19
|
+
putc '.'
|
|
20
|
+
puts if @marker_counter == @bar_length # after the last marker is printed, add a new_line
|
|
21
|
+
$stdout.flush
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|