mysql_truck 0.6.4 → 0.6.6
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/Gemfile +6 -0
- data/bin/mysql_truck +4 -0
- data/lib/mysql_truck/dumper.rb +1 -1
- data/lib/mysql_truck/loader.rb +26 -22
- data/lib/mysql_truck/version.rb +1 -1
- data/test/fake_aws.rb +69 -0
- data/test/lib/mysql_truck/loader_test.rb +82 -0
- data/test/test_helper.rb +4 -0
- metadata +9 -3
data/Gemfile
CHANGED
data/bin/mysql_truck
CHANGED
@@ -73,6 +73,10 @@ parser = OptionParser.new do |opts|
|
|
73
73
|
options[:skip_data_for_tables] = tables.split(",")
|
74
74
|
end
|
75
75
|
|
76
|
+
opts.on("--skip-all-data", "Only load schema") do
|
77
|
+
options[:skip_all_data] = true
|
78
|
+
end
|
79
|
+
|
76
80
|
opts.on("-o", "--only-tables TABLES",
|
77
81
|
"List of tables to dump/load.") do |tables|
|
78
82
|
options[:only_tables] = tables.split(",")
|
data/lib/mysql_truck/dumper.rb
CHANGED
@@ -49,7 +49,7 @@ module MysqlTruck
|
|
49
49
|
# Dump data
|
50
50
|
puts "Writing data for #{table} ..."
|
51
51
|
benchmark do
|
52
|
-
puts `mysql #{db_connection_options} --skip-column-names --batch -e "select * from #{table}" | lzop -6 > #{filename(table)[:compressed_data_file]} 2>/var/log/mysql_truck_dump.log`
|
52
|
+
puts `mysql #{db_connection_options} --skip-column-names --batch -e "select * from #{table}" | sed -e 's/\tNULL/\t\\\\N/g'| lzop -6 > #{filename(table)[:compressed_data_file]} 2>/var/log/mysql_truck_dump.log`
|
53
53
|
if $?.exitstatus != 0
|
54
54
|
puts "Command did not execute successfully"
|
55
55
|
end
|
data/lib/mysql_truck/loader.rb
CHANGED
@@ -19,7 +19,6 @@ module MysqlTruck
|
|
19
19
|
end
|
20
20
|
|
21
21
|
def load_backup
|
22
|
-
|
23
22
|
# Default to latest backup
|
24
23
|
backup_date_str = config[:backup_date] || backups.first.split("/").last
|
25
24
|
|
@@ -30,7 +29,6 @@ module MysqlTruck
|
|
30
29
|
puts "Download & decompressing backups"
|
31
30
|
puts "-------------------"
|
32
31
|
|
33
|
-
|
34
32
|
@bucket.keys(:prefix => s3_path).each do |key|
|
35
33
|
next if key.to_s.match(/\/$/)
|
36
34
|
next unless (filename = download_file(key))
|
@@ -68,7 +66,7 @@ module MysqlTruck
|
|
68
66
|
csv_data_file = tmp_path.join("#{table}.csv")
|
69
67
|
tsv_data_file = tmp_path.join("#{table}.data.tsv")
|
70
68
|
|
71
|
-
|
69
|
+
# Create table
|
72
70
|
if schema_file.exist?
|
73
71
|
print " - Loading schema: #{File.basename(schema_file)} ... "
|
74
72
|
execute_sql_file(table, backup_date_str, schema_file)
|
@@ -84,23 +82,26 @@ module MysqlTruck
|
|
84
82
|
next
|
85
83
|
end
|
86
84
|
|
87
|
-
|
88
|
-
if
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
85
|
+
# Load data
|
86
|
+
if !config[:skip_all_data]
|
87
|
+
if data_file.exist?
|
88
|
+
print " - Importing #{File.basename(data_file)} ... "
|
89
|
+
execute_sql_file(table, backup_date_str, data_file)
|
90
|
+
data_file.delete
|
91
|
+
|
92
|
+
elsif csv_data_file.exist?
|
93
|
+
print " - Importing #{File.basename(csv_data_file)} ... "
|
94
|
+
csv_data_file = import_csv_file(table, backup_date_str, csv_data_file)
|
95
|
+
File.delete(csv_data_file)
|
96
|
+
|
97
|
+
elsif tsv_data_file.exist?
|
98
|
+
print " - Importing #{File.basename(tsv_data_file)} ... "
|
99
|
+
tsv_data_file = import_tsv_file(table, backup_date_str, tsv_data_file)
|
100
|
+
File.delete(tsv_data_file)
|
101
|
+
end
|
102
102
|
end
|
103
103
|
|
104
|
+
# Add indices
|
104
105
|
if index_file.exist?
|
105
106
|
print " - Adding indices: #{File.basename(index_file)} ... "
|
106
107
|
execute_sql_file(table, backup_date_str, index_file)
|
@@ -191,8 +192,7 @@ module MysqlTruck
|
|
191
192
|
|
192
193
|
def should_download_file?(filename)
|
193
194
|
table_name = filename.gsub(/\..*\..*$/, '')
|
194
|
-
|
195
|
-
if only_tables.empty? and skip_data_for_tables.empty?
|
195
|
+
if only_tables.empty? and skip_data_for_tables.empty? and !config[:skip_all_data]
|
196
196
|
return true
|
197
197
|
end
|
198
198
|
|
@@ -202,7 +202,8 @@ module MysqlTruck
|
|
202
202
|
return only_tables.include?(table_name)
|
203
203
|
end
|
204
204
|
|
205
|
-
if filename.match(/\.data\.sql\.gz$/)
|
205
|
+
if filename.match(/\.data\.(sql|tsv)\.(lzo|gz)$/)
|
206
|
+
return false if config[:skip_all_data]
|
206
207
|
is_data = true
|
207
208
|
is_schema = false
|
208
209
|
else
|
@@ -210,8 +211,10 @@ module MysqlTruck
|
|
210
211
|
is_schema = true
|
211
212
|
end
|
212
213
|
|
214
|
+
return true if is_schema && config[:skip_all_data]
|
215
|
+
|
213
216
|
if !skip_data_for_tables.empty?
|
214
|
-
if is_schema
|
217
|
+
if is_schema || (is_data && !skip_data_for_tables.include?(table_name))
|
215
218
|
return true
|
216
219
|
end
|
217
220
|
end
|
@@ -237,6 +240,7 @@ module MysqlTruck
|
|
237
240
|
end
|
238
241
|
@backups = @backups.sort { |a,b| b <=> a }
|
239
242
|
end
|
243
|
+
|
240
244
|
@backups
|
241
245
|
end
|
242
246
|
|
data/lib/mysql_truck/version.rb
CHANGED
data/test/fake_aws.rb
ADDED
@@ -0,0 +1,69 @@
|
|
1
|
+
require 'hashie'
|
2
|
+
|
3
|
+
class FakeAws
|
4
|
+
|
5
|
+
def initialize
|
6
|
+
@files = []
|
7
|
+
end
|
8
|
+
|
9
|
+
def bucket(bucket_name)
|
10
|
+
BucketContent.new(bucket_name, @files)
|
11
|
+
end
|
12
|
+
|
13
|
+
def add_fake_file(path)
|
14
|
+
@files << path
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
|
19
|
+
class BucketContent
|
20
|
+
|
21
|
+
def initialize(name, data)
|
22
|
+
@data = data
|
23
|
+
@name = name
|
24
|
+
end
|
25
|
+
|
26
|
+
def name
|
27
|
+
@name
|
28
|
+
end
|
29
|
+
|
30
|
+
def s3
|
31
|
+
FakeS3.new(@data)
|
32
|
+
end
|
33
|
+
|
34
|
+
def keys(configs)
|
35
|
+
prefix = configs[:prefix]
|
36
|
+
@data.map do |file|
|
37
|
+
Hashie::Mash.new({name: file})
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
|
43
|
+
class FakeS3
|
44
|
+
|
45
|
+
def initialize(data)
|
46
|
+
@data = data
|
47
|
+
end
|
48
|
+
|
49
|
+
def interface
|
50
|
+
#TODO calculate common_prefixes
|
51
|
+
Interface.new(@data)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
class Interface
|
56
|
+
|
57
|
+
def initialize(data)
|
58
|
+
@data = data
|
59
|
+
end
|
60
|
+
|
61
|
+
def incrementally_list_bucket(bucket_name, options)
|
62
|
+
yield common_prefixes: [@data.first.split('/')[0..2].join('/') ]
|
63
|
+
end
|
64
|
+
|
65
|
+
def get(bucket_name, key_name)
|
66
|
+
yield 'content'
|
67
|
+
end
|
68
|
+
|
69
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
module MysqlTruck
|
4
|
+
class LoaderTest < Minitest::Unit::TestCase
|
5
|
+
|
6
|
+
def setup
|
7
|
+
mock_aws_with_fake_backups('2013-01-01', ['users', 'mixes'])
|
8
|
+
end
|
9
|
+
|
10
|
+
def test_loads_old_backups_with_only_tables
|
11
|
+
config = { s3_access_key: 'key', s3_secret_access_key: 'password', :only_tables => ['users'] }
|
12
|
+
loader = MysqlTruck::Loader.new(config)
|
13
|
+
|
14
|
+
assert loader.should_download_file?('users.data.sql.gz')
|
15
|
+
assert loader.should_download_file?('users.indices.sql.gz')
|
16
|
+
assert loader.should_download_file?('users.no_index.sql.gz')
|
17
|
+
|
18
|
+
|
19
|
+
refute loader.should_download_file?('mixes.data.sql.gz')
|
20
|
+
refute loader.should_download_file?('mixes.indices.sql.gz')
|
21
|
+
refute loader.should_download_file?('mixes.no_index.sql.gz')
|
22
|
+
end
|
23
|
+
|
24
|
+
def test_old_backups_with_skip_data_for_tables
|
25
|
+
config = { s3_access_key: 'key', s3_secret_access_key: 'password', :skip_data_for_tables => ['users'] }
|
26
|
+
loader = MysqlTruck::Loader.new(config)
|
27
|
+
|
28
|
+
|
29
|
+
#refutes data files for the ones you want to ignore
|
30
|
+
refute loader.should_download_file?('users.data.sql.gz')
|
31
|
+
assert loader.should_download_file?('users.indices.sql.gz')
|
32
|
+
assert loader.should_download_file?('users.no_index.sql.gz')
|
33
|
+
|
34
|
+
assert loader.should_download_file?('mixes.data.sql.gz')
|
35
|
+
assert loader.should_download_file?('mixes.indices.sql.gz')
|
36
|
+
assert loader.should_download_file?('mixes.no_index.sql.gz')
|
37
|
+
end
|
38
|
+
|
39
|
+
def test_new_backups_with_only_tables
|
40
|
+
config = { s3_access_key: 'key', s3_secret_access_key: 'password', :only_tables => ['users'] }
|
41
|
+
loader = MysqlTruck::Loader.new(config)
|
42
|
+
|
43
|
+
assert loader.should_download_file?('users.data.tsv.lzo')
|
44
|
+
assert loader.should_download_file?('users.indices.sql.lzo')
|
45
|
+
assert loader.should_download_file?('users.no_index.sql.lzo')
|
46
|
+
|
47
|
+
|
48
|
+
refute loader.should_download_file?('mixes.data.tsv.lzo')
|
49
|
+
refute loader.should_download_file?('mixes.indices.sql.lzo')
|
50
|
+
refute loader.should_download_file?('mixes.no_index.sql.lzo')
|
51
|
+
end
|
52
|
+
|
53
|
+
def test_new_backups_with_with_skip_data_for_tables
|
54
|
+
config = { s3_access_key: 'key', s3_secret_access_key: 'password', :skip_data_for_tables => ['users'] }
|
55
|
+
loader = MysqlTruck::Loader.new(config)
|
56
|
+
|
57
|
+
#refutes data files for the ones you want to ignore
|
58
|
+
refute loader.should_download_file?('users.data.tsv.lzo')
|
59
|
+
assert loader.should_download_file?('users.indices.sql.lzo')
|
60
|
+
assert loader.should_download_file?('users.no_index.sql.lzo')
|
61
|
+
|
62
|
+
assert loader.should_download_file?('mixes.data.tsv.lzo')
|
63
|
+
assert loader.should_download_file?('mixes.indices.sql.lzo')
|
64
|
+
assert loader.should_download_file?('mixes.no_index.sql.lzo')
|
65
|
+
end
|
66
|
+
|
67
|
+
def mock_aws_with_fake_backups(date, tables)
|
68
|
+
fake_aws = FakeAws.new
|
69
|
+
|
70
|
+
tables.each do |table|
|
71
|
+
base_name = "mysql/8trackscom/#{date}/#{table}"
|
72
|
+
|
73
|
+
fake_aws.add_fake_file("#{base_name}.data.sql.gz")
|
74
|
+
fake_aws.add_fake_file("#{base_name}.indices.sql.gz")
|
75
|
+
fake_aws.add_fake_file("#{base_name}.no_index.sql.gz")
|
76
|
+
end
|
77
|
+
|
78
|
+
RightAws::S3.expects(:new).returns(fake_aws)
|
79
|
+
end
|
80
|
+
|
81
|
+
end
|
82
|
+
end
|
data/test/test_helper.rb
ADDED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mysql_truck
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.6.
|
4
|
+
version: 0.6.6
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -11,7 +11,7 @@ authors:
|
|
11
11
|
autorequire:
|
12
12
|
bindir: bin
|
13
13
|
cert_chain: []
|
14
|
-
date: 2013-02-
|
14
|
+
date: 2013-02-27 00:00:00.000000000 Z
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
17
17
|
name: right_aws
|
@@ -66,6 +66,9 @@ files:
|
|
66
66
|
- lib/mysql_truck/loader.rb
|
67
67
|
- lib/mysql_truck/version.rb
|
68
68
|
- mysql_truck.gemspec
|
69
|
+
- test/fake_aws.rb
|
70
|
+
- test/lib/mysql_truck/loader_test.rb
|
71
|
+
- test/test_helper.rb
|
69
72
|
homepage: ''
|
70
73
|
licenses: []
|
71
74
|
post_install_message:
|
@@ -90,4 +93,7 @@ rubygems_version: 1.8.23
|
|
90
93
|
signing_key:
|
91
94
|
specification_version: 3
|
92
95
|
summary: Mysql database backup tool. Dumps/Loads to/from S3.
|
93
|
-
test_files:
|
96
|
+
test_files:
|
97
|
+
- test/fake_aws.rb
|
98
|
+
- test/lib/mysql_truck/loader_test.rb
|
99
|
+
- test/test_helper.rb
|