lhm 1.0.0.rc.1 → 1.0.0.rc2

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.
@@ -3,7 +3,7 @@ rvm:
3
3
  - 1.9.2
4
4
  - 1.9.3
5
5
  before_script:
6
- - "mysql -e 'create database large_hadron_migrator;'"
6
+ - "mysql -e 'create database lhm;'"
7
7
  branches:
8
8
  only:
9
9
  - master
@@ -1,8 +1,18 @@
1
- # 1.0.0-RC1
1
+ # 1.0.0.rc2 (January 18, 2012)
2
2
 
3
- * rewrite.
3
+ * Speedup migrations for tables with large ids
4
+ * Fix conversion of milliseconds to seconds
5
+ * Fix handling of sql errors
6
+ * Add helper to create unique index
7
+ * Allow index creation on prefix of column
8
+ * Quote column names on index creation
9
+ * Remove ambiguous method signature
10
+ * Documentation fix
11
+ * 1.8.7 compatibility
12
+
13
+ # 1.0.0.rc1 (January 15, 2012)
4
14
 
5
- # 0.9.1
15
+ * rewrite.
6
16
 
7
17
  # 0.2.1 (November 26, 2011)
8
18
 
data/README.md CHANGED
@@ -42,11 +42,11 @@ twitter solution [1], it does not require the presence of an indexed
42
42
 
43
43
  ## Usage
44
44
 
45
- After including Lhm, `hadron_change_table` becomes available
45
+ After extending Lhm, `hadron_change_table` becomes available
46
46
  with the following methods:
47
47
 
48
48
  class MigrateArbitrary < ActiveRecord::Migration
49
- include Lhm
49
+ extend Lhm
50
50
 
51
51
  def self.up
52
52
  hadron_change_table(:users) do |t|
data/Rakefile CHANGED
@@ -1,4 +1,7 @@
1
1
  require 'rake/testtask'
2
+ require 'bundler'
3
+
4
+ Bundler::GemHelper.install_tasks
2
5
 
3
6
  Rake::TestTask.new("unit") do |t|
4
7
  t.libs.push "lib"
@@ -3,8 +3,6 @@
3
3
  lib = File.expand_path('../lib', __FILE__)
4
4
  $:.unshift(lib) unless $:.include?(lib)
5
5
 
6
- puts $:.inspect
7
-
8
6
  require 'lhm'
9
7
 
10
8
  Gem::Specification.new do |s|
@@ -23,7 +21,9 @@ Gem::Specification.new do |s|
23
21
 
24
22
  # this should be a real dependency, but we're using a different gem in our code
25
23
  s.add_development_dependency "mysql", "~> 2.8.1"
26
- s.add_development_dependency "rspec", "=1.3.1"
24
+ s.add_development_dependency "minitest", "= 2.10.0"
27
25
  s.add_development_dependency "rake"
26
+
27
+ s.add_dependency "activerecord"
28
28
  end
29
29
 
data/lib/lhm.rb CHANGED
@@ -8,7 +8,7 @@ require 'lhm/invoker'
8
8
  require 'lhm/migration'
9
9
 
10
10
  module Lhm
11
- VERSION = "1.0.0.rc.1"
11
+ VERSION = "1.0.0.rc2"
12
12
 
13
13
  def hadron_change_table(table_name, chunk_options = {}, &block)
14
14
  origin = Table.parse(table_name, connection)
@@ -29,7 +29,7 @@ module Lhm
29
29
 
30
30
  def up_to(limit)
31
31
  traversable_chunks_up_to(limit).times do |n|
32
- yield(bottom(n + 1), top(n + 1, limit)) && sleep(throttle_seconds)
32
+ yield(bottom(n + 1), top(n + 1, limit))
33
33
  end
34
34
  end
35
35
 
@@ -59,14 +59,18 @@ module Lhm
59
59
 
60
60
  def execute
61
61
  up_to(@limit) do |lowest, highest|
62
- print "."
62
+ affected_rows = update(copy(lowest, highest))
63
+
64
+ if affected_rows > 0
65
+ sleep(throttle_seconds)
66
+ end
63
67
 
64
- sql copy(lowest, highest)
68
+ print "."
65
69
  end
66
70
  end
67
71
 
68
72
  def throttle_seconds
69
- @throttle / 100.0
73
+ @throttle / 1000.0
70
74
  end
71
75
  end
72
76
  end
@@ -17,9 +17,7 @@ module Lhm
17
17
 
18
18
  def validate; end
19
19
 
20
- def revert
21
- raise NotImplementedError.new(self.class.name)
22
- end
20
+ def revert; end
23
21
 
24
22
  def run(&block)
25
23
  validate
@@ -56,14 +54,19 @@ module Lhm
56
54
  end
57
55
 
58
56
  def sql(statements)
59
- [*statements].each do |statement|
60
- begin
61
- @connection.execute(statement)
62
- rescue Mysql::Error => e
63
- revert
64
- error "#{ statement } failed: #{ e.inspect }"
65
- end
57
+ [statements].flatten.each { |statement| @connection.execute(statement) }
58
+ rescue ActiveRecord::StatementInvalid, Mysql::Error => e
59
+ revert
60
+ error e.message
61
+ end
62
+
63
+ def update(statements)
64
+ [statements].flatten.inject(0) do |memo, statement|
65
+ memo += @connection.update(statement)
66
66
  end
67
+ rescue ActiveRecord::StatementInvalid, Mysql::Error => e
68
+ revert
69
+ error e.message
67
70
  end
68
71
  end
69
72
  end
@@ -13,7 +13,7 @@ module Lhm
13
13
  end
14
14
 
15
15
  def common
16
- @origin.columns.keys & @destination.columns.keys
16
+ (@origin.columns.keys & @destination.columns.keys).sort
17
17
  end
18
18
 
19
19
  def escaped
@@ -49,9 +49,10 @@ module Lhm
49
49
  [
50
50
  "set @lhm_auto_commit = @@session.autocommit",
51
51
  "set session autocommit = 0",
52
- *yield,
52
+ yield,
53
53
  "set session autocommit = @lhm_auto_commit"
54
- ]
54
+
55
+ ].flatten
55
56
  end
56
57
 
57
58
  #
@@ -61,7 +61,20 @@ module Lhm
61
61
  #
62
62
 
63
63
  def add_index(cols)
64
- ddl = "create index `%s` on %s" % [@origin.idx_name(cols), idx_spec(cols)]
64
+ ddl = "create index `%s` on %s" % idx_parts(cols)
65
+ statements << ddl.strip
66
+ end
67
+
68
+ #
69
+ # Add a unique index to a table:
70
+ #
71
+ # hadron_change_table("users") do |t|
72
+ # t.add_unique_index([:comment, :created_at])
73
+ # end
74
+ #
75
+
76
+ def add_unique_index(cols)
77
+ ddl = "create unique index `%s` on %s" % idx_parts(cols)
65
78
  statements << ddl.strip
66
79
  end
67
80
 
@@ -73,7 +86,7 @@ module Lhm
73
86
  # end
74
87
  #
75
88
 
76
- def remove_index(*cols)
89
+ def remove_index(cols)
77
90
  ddl = "drop index `%s` on `%s`" % [@origin.idx_name(cols), @name]
78
91
  statements << ddl.strip
79
92
  end
@@ -118,7 +131,11 @@ module Lhm
118
131
  end
119
132
 
120
133
  def idx_spec(cols)
121
- "#{ @name }(#{ [*cols].map(&:to_s).join(', ') })"
134
+ "`#{ @name }` (#{ Array(cols).map(&:to_s).join(', ') })"
135
+ end
136
+
137
+ def idx_parts(cols)
138
+ [@origin.idx_name(cols), idx_spec(cols)]
122
139
  end
123
140
  end
124
141
  end
@@ -24,7 +24,8 @@ module Lhm
24
24
  end
25
25
 
26
26
  def idx_name(cols)
27
- "index_#{ @name }_on_" + [*cols].join("_and_")
27
+ column_part = Array(cols).map { |c| c.to_s.sub(/\(.*/, "") }.join("_and_")
28
+ "index_#{ @name }_on_#{ column_part }"
28
29
  end
29
30
 
30
31
  def self.parse(table_name, connection)
@@ -9,7 +9,6 @@ require 'active_record'
9
9
  require 'lhm/table'
10
10
 
11
11
  module IntegrationHelper
12
- delegate :select_one, :select_value, :execute, :to => :connection
13
12
 
14
13
  #
15
14
  # Connectivity
@@ -30,6 +29,18 @@ module IntegrationHelper
30
29
  ActiveRecord::Base.connection
31
30
  end
32
31
 
32
+ def select_one(*args)
33
+ connection.select_one(*args)
34
+ end
35
+
36
+ def select_value(*args)
37
+ connection.select_value(*args)
38
+ end
39
+
40
+ def execute(*args)
41
+ connection.execute(*args)
42
+ end
43
+
33
44
  #
34
45
  # Test Data
35
46
  #
@@ -66,9 +77,9 @@ module IntegrationHelper
66
77
  select_value(query).to_i
67
78
  end
68
79
 
69
- def key?(table, cols)
70
- query = "show indexes in #{ table.name } where key_name = '#{ table.idx_name(cols) }'"
80
+ def key?(table, cols, type = :non_unique)
81
+ non_unique = type == :non_unique ? 1 : 0
82
+ query = "show indexes in #{ table.name } where key_name = '#{ table.idx_name(cols) }' and non_unique = #{ non_unique }"
71
83
  !!select_value(query)
72
84
  end
73
85
  end
74
-
@@ -55,9 +55,17 @@ describe Lhm do
55
55
  key?(table_read("users"), ["comment", "created_at"]).must_equal(true)
56
56
  end
57
57
 
58
+ it "should add a unqiue index" do
59
+ hadron_change_table("users") do |t|
60
+ t.add_unique_index(:comment)
61
+ end
62
+
63
+ key?(table_read(:users), :comment, :unique).must_equal(true)
64
+ end
65
+
58
66
  it "should remove an index" do
59
67
  hadron_change_table("users") do |t|
60
- t.remove_index(:username, :created_at)
68
+ t.remove_index([:username, :created_at])
61
69
  end
62
70
 
63
71
  key?(table_read("users"), ["username", "created_at"]).must_equal(false)
@@ -21,7 +21,23 @@ describe Lhm::Migrator do
21
21
  @creator.add_index(["a", "b"])
22
22
 
23
23
  @creator.statements.must_equal([
24
- "create index `index_alt_on_a_and_b` on lhmn_alt(a, b)"
24
+ "create index `index_alt_on_a_and_b` on `lhmn_alt` (a, b)"
25
+ ])
26
+ end
27
+
28
+ it "should add an index with prefixed columns" do
29
+ @creator.add_index(["a(10)", "b"])
30
+
31
+ @creator.statements.must_equal([
32
+ "create index `index_alt_on_a_and_b` on `lhmn_alt` (a(10), b)"
33
+ ])
34
+ end
35
+
36
+ it "should add an unique index" do
37
+ @creator.add_unique_index(["a(10)", :b])
38
+
39
+ @creator.statements.must_equal([
40
+ "create unique index `index_alt_on_a_and_b` on `lhmn_alt` (a(10), b)"
25
41
  ])
26
42
  end
27
43
 
@@ -25,11 +25,23 @@ describe Lhm::Table do
25
25
  must_equal("index_users_on_name")
26
26
  end
27
27
 
28
- it "should name index with a multiple columns" do
28
+ it "should name index with multiple columns" do
29
29
  @table.
30
30
  idx_name(["name", "firstname"]).
31
31
  must_equal("index_users_on_name_and_firstname")
32
32
  end
33
+
34
+ it "should name index with prefixed column" do
35
+ @table.
36
+ idx_name(["name(10)", "firstname"]).
37
+ must_equal("index_users_on_name_and_firstname")
38
+ end
39
+
40
+ it "should name index with column names given as symbol" do
41
+ @table.
42
+ idx_name([:name, :firstname]).
43
+ must_equal("index_users_on_name_and_firstname")
44
+ end
33
45
  end
34
46
 
35
47
  describe "constraints" do
metadata CHANGED
@@ -1,14 +1,8 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lhm
3
3
  version: !ruby/object:Gem::Version
4
- prerelease: true
5
- segments:
6
- - 1
7
- - 0
8
- - 0
9
- - rc
10
- - 1
11
- version: 1.0.0.rc.1
4
+ prerelease: 6
5
+ version: 1.0.0.rc2
12
6
  platform: ruby
13
7
  authors:
14
8
  - SoundCloud
@@ -19,7 +13,7 @@ autorequire:
19
13
  bindir: bin
20
14
  cert_chain: []
21
15
 
22
- date: 2012-01-16 00:00:00 +01:00
16
+ date: 2012-01-18 00:00:00 +01:00
23
17
  default_executable:
24
18
  dependencies:
25
19
  - !ruby/object:Gem::Dependency
@@ -30,26 +24,18 @@ dependencies:
30
24
  requirements:
31
25
  - - ~>
32
26
  - !ruby/object:Gem::Version
33
- segments:
34
- - 2
35
- - 8
36
- - 1
37
27
  version: 2.8.1
38
28
  type: :development
39
29
  version_requirements: *id001
40
30
  - !ruby/object:Gem::Dependency
41
- name: rspec
31
+ name: minitest
42
32
  prerelease: false
43
33
  requirement: &id002 !ruby/object:Gem::Requirement
44
34
  none: false
45
35
  requirements:
46
36
  - - "="
47
37
  - !ruby/object:Gem::Version
48
- segments:
49
- - 1
50
- - 3
51
- - 1
52
- version: 1.3.1
38
+ version: 2.10.0
53
39
  type: :development
54
40
  version_requirements: *id002
55
41
  - !ruby/object:Gem::Dependency
@@ -60,11 +46,20 @@ dependencies:
60
46
  requirements:
61
47
  - - ">="
62
48
  - !ruby/object:Gem::Version
63
- segments:
64
- - 0
65
49
  version: "0"
66
50
  type: :development
67
51
  version_requirements: *id003
52
+ - !ruby/object:Gem::Dependency
53
+ name: activerecord
54
+ prerelease: false
55
+ requirement: &id004 !ruby/object:Gem::Requirement
56
+ none: false
57
+ requirements:
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ version: "0"
61
+ type: :runtime
62
+ version_requirements: *id004
68
63
  description: Migrate large tables without downtime by copying to a temporary table in chunks. The old table is not dropped. Instead, it is moved to timestamp_table_name for verification.
69
64
  email: rany@soundcloud.com, tobi@soundcloud.com, ts@soundcloud.com
70
65
  executables: []
@@ -82,7 +77,6 @@ files:
82
77
  - LICENSE
83
78
  - README.md
84
79
  - Rakefile
85
- - TODO
86
80
  - lhm.gemspec
87
81
  - lib/lhm.rb
88
82
  - lib/lhm/chunker.rb
@@ -125,23 +119,17 @@ required_ruby_version: !ruby/object:Gem::Requirement
125
119
  requirements:
126
120
  - - ">="
127
121
  - !ruby/object:Gem::Version
128
- segments:
129
- - 0
130
122
  version: "0"
131
123
  required_rubygems_version: !ruby/object:Gem::Requirement
132
124
  none: false
133
125
  requirements:
134
126
  - - ">"
135
127
  - !ruby/object:Gem::Version
136
- segments:
137
- - 1
138
- - 3
139
- - 1
140
128
  version: 1.3.1
141
129
  requirements: []
142
130
 
143
131
  rubyforge_project:
144
- rubygems_version: 1.3.7
132
+ rubygems_version: 1.5.0
145
133
  signing_key:
146
134
  specification_version: 3
147
135
  summary: online schema changer for mysql
data/TODO DELETED
@@ -1,11 +0,0 @@
1
- todo
2
-
3
- . locked_switcher
4
- . schema_creator
5
- . chunker
6
-
7
- checklist
8
-
9
- . consider entanglement epoch
10
- - should not lose changes due to low epoch
11
-