filecluster 0.5.14 → 0.5.15
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +3 -0
- data/.ssh/.keep +0 -0
- data/Dockerfile +40 -0
- data/Gemfile +1 -0
- data/README_RU.md +32 -0
- data/bin/fc-daemon +4 -1
- data/bin/fc-manage +8 -0
- data/bin/fc-setup-db +2 -2
- data/docker-compose-mysql56.yaml +35 -0
- data/docker-compose.yaml +35 -0
- data/docker/Dockerfile.sshd +17 -0
- data/docker/development.env +7 -0
- data/entrypoint.sh +19 -0
- data/filecluster.gemspec +2 -0
- data/lib/autosync.rb +149 -0
- data/lib/daemon.rb +17 -1
- data/lib/daemon/autosync_thread.rb +16 -0
- data/lib/daemon/global_daemon_thread.rb +1 -1
- data/lib/daemon/update_tasks_thread.rb +1 -1
- data/lib/fc/db.rb +5 -1
- data/lib/fc/storage.rb +3 -3
- data/lib/fc/var.rb +20 -1
- data/lib/fc/version.rb +1 -1
- data/lib/iostat.rb +48 -0
- data/lib/manage.rb +3 -1
- data/lib/manage/autosync.rb +53 -0
- data/lib/manage/copy_speed.rb +1 -1
- data/lib/manage/storages.rb +57 -1
- data/test/autosync_test.rb +186 -0
- data/test/daemon_test.rb +44 -31
- data/test/db_test.rb +28 -21
- data/test/error_test.rb +3 -3
- data/test/functional_test.rb +21 -20
- data/test/helper.rb +8 -2
- data/test/storage_sync_test.rb +7 -7
- metadata +44 -2
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'autosync'
|
2
|
+
|
3
|
+
class AutosyncThread < BaseThread
|
4
|
+
attr_accessor :start_time, :files_to_delete, :items_to_delete
|
5
|
+
def go(storages)
|
6
|
+
storages.each do |storage|
|
7
|
+
$log.debug("AutosyncThread: Run storage synchronization for #{storage.name}")
|
8
|
+
Autosync.new(storage).run
|
9
|
+
storage.reload
|
10
|
+
storage.autosync_at = Time.now.to_i
|
11
|
+
storage.save
|
12
|
+
$log.debug("AutosyncThread: Finish storage synchronization for #{storage.name}")
|
13
|
+
break if $exit_signal
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -39,8 +39,8 @@ class GlobalDaemonThread < BaseThread
|
|
39
39
|
"ist.item_id = i.id AND i.copies IN (#{copies}) AND i.status = 'ready' AND ist.status <> 'delete' GROUP BY i.id LIMIT #{limit}"
|
40
40
|
r = FC::DB.query(sql)
|
41
41
|
r.each do |row|
|
42
|
-
$log.info("GlobalDaemonThread: new item_storage for item #{row['item_id']}")
|
43
42
|
item_storages = row['storages'].split(',')
|
43
|
+
$log.info("GlobalDaemonThread: new item_storage for item #{row['item_id']}, exclude #{item_storages}")
|
44
44
|
if row['item_copies'] != item_storages.count
|
45
45
|
$log.warn("GlobalDaemonThread: ItemStorage count <> item.copies for item #{row['item_id']}")
|
46
46
|
elsif item_storages.count >= policy.copies.to_i
|
@@ -9,7 +9,7 @@ class UpdateTasksThread < BaseThread
|
|
9
9
|
count = 0
|
10
10
|
limit = FC::Var.get("daemon_tasks_#{type}_group_limit", 1000).to_i
|
11
11
|
tasks = (type == :copy ? $tasks_copy : $tasks_delete)
|
12
|
-
$storages.each do |storage|
|
12
|
+
$storages.select { |storage| storage.write_weight.to_i >= 0 }.each do |storage|
|
13
13
|
tasks[storage.name] = [] unless tasks[storage.name]
|
14
14
|
ids = tasks[storage.name].map(&:id) + $curr_tasks.compact.map(&:id)
|
15
15
|
if ids.length > limit*2
|
data/lib/fc/db.rb
CHANGED
@@ -147,7 +147,7 @@ module FC
|
|
147
147
|
id bigint NOT NULL AUTO_INCREMENT,
|
148
148
|
name varchar(1024) NOT NULL DEFAULT '',
|
149
149
|
tag varchar(255) DEFAULT NULL,
|
150
|
-
outer_id
|
150
|
+
outer_id bigint DEFAULT NULL,
|
151
151
|
policy_id int NOT NULL,
|
152
152
|
dir tinyint(1) NOT NULL DEFAULT 0,
|
153
153
|
size bigint NOT NULL DEFAULT 0,
|
@@ -336,5 +336,9 @@ module FC
|
|
336
336
|
FC::DB.query("ALTER TABLE #{@prefix}storages ADD COLUMN auto_size bigint(20) DEFAULT 0")
|
337
337
|
end
|
338
338
|
|
339
|
+
def self.migrate_5
|
340
|
+
FC::DB.query("ALTER TABLE #{@prefix}storages ADD COLUMN autosync_at bigint(11) DEFAULT 0")
|
341
|
+
end
|
342
|
+
|
339
343
|
end
|
340
344
|
end
|
data/lib/fc/storage.rb
CHANGED
@@ -4,7 +4,7 @@ require 'fileutils'
|
|
4
4
|
|
5
5
|
module FC
|
6
6
|
class Storage < DbBase
|
7
|
-
set_table :storages, 'name, host, dc, path, url, size, size_limit, check_time, copy_storages, url_weight, write_weight, auto_size'
|
7
|
+
set_table :storages, 'name, host, dc, path, url, size, size_limit, check_time, copy_storages, url_weight, write_weight, auto_size, autosync_at'
|
8
8
|
|
9
9
|
class << self
|
10
10
|
attr_accessor :check_time_limit, :storages_cache_time, :get_copy_storages_mutex
|
@@ -124,7 +124,7 @@ module FC
|
|
124
124
|
raise r if $?.exitstatus != 0
|
125
125
|
else
|
126
126
|
local_path += '/' if File.stat(local_path).directory?
|
127
|
-
cmd = "ionice -c 2 -n 7 rsync -e \"ssh -o StrictHostKeyChecking=no\" -a #{FC::Storage.speed_limit_to_rsync_opt(speed_limit)}--rsync-path=\"#{recreate_dirs_cmd} && ionice -c 2 -n 7 rsync\" #{local_path.shellescape} #{self.host}:\"#{dst_path.shellescape}\""
|
127
|
+
cmd = "ionice -c 2 -n 7 rsync -e \"ssh -o StrictHostKeyChecking=no\" -a --no-t #{FC::Storage.speed_limit_to_rsync_opt(speed_limit)}--rsync-path=\"#{recreate_dirs_cmd} && ionice -c 2 -n 7 rsync\" #{local_path.shellescape} #{self.host}:\"#{dst_path.shellescape}\""
|
128
128
|
r = `#{cmd} 2>&1`
|
129
129
|
raise r if $?.exitstatus != 0
|
130
130
|
end
|
@@ -142,7 +142,7 @@ module FC
|
|
142
142
|
r = `#{cmd} 2>&1`
|
143
143
|
src_path += '/' if $?.exitstatus == 0
|
144
144
|
|
145
|
-
cmd = "ionice -c 2 -n 7 rsync -e \"ssh -o StrictHostKeyChecking=no\" -a #{FC::Storage.speed_limit_to_rsync_opt(speed_limit)}--rsync-path=\"ionice -c 2 -n 7 rsync\" #{self.host}:\"#{src_path.shellescape}\" #{local_path.shellescape}"
|
145
|
+
cmd = "ionice -c 2 -n 7 rsync -e \"ssh -o StrictHostKeyChecking=no\" -a --no-t #{FC::Storage.speed_limit_to_rsync_opt(speed_limit)}--rsync-path=\"ionice -c 2 -n 7 rsync\" #{self.host}:\"#{src_path.shellescape}\" #{local_path.shellescape}"
|
146
146
|
r = `#{cmd} 2>&1`
|
147
147
|
raise r if $?.exitstatus != 0
|
148
148
|
end
|
data/lib/fc/var.rb
CHANGED
@@ -35,7 +35,26 @@ module FC
|
|
35
35
|
end
|
36
36
|
@all_vars
|
37
37
|
end
|
38
|
-
|
38
|
+
|
39
|
+
def self.get_autosync
|
40
|
+
sync_interval = {
|
41
|
+
'all' => 604_800 # default 7 days in seconds
|
42
|
+
}
|
43
|
+
sync_interval.merge! Hash[get('autosync_intervals').to_s.split(';;').map { |v| v.split('::') }]
|
44
|
+
sync_interval.each { |host, val| sync_interval[host] = val.to_i > 0 ? val.to_i : 0 }
|
45
|
+
end
|
46
|
+
|
47
|
+
def self.set_autosync(host, val)
|
48
|
+
current = get_autosync
|
49
|
+
if val.nil? || val == ''
|
50
|
+
current.delete(host)
|
51
|
+
else
|
52
|
+
current[host] = val
|
53
|
+
end
|
54
|
+
list = current.map { |h, v| "#{h}::#{v}" }.join(';;')
|
55
|
+
set('autosync_intervals', list)
|
56
|
+
end
|
57
|
+
|
39
58
|
def self.get_speed_limits
|
40
59
|
limits = {
|
41
60
|
'all' => nil
|
data/lib/fc/version.rb
CHANGED
data/lib/iostat.rb
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'open3'
|
2
|
+
require 'shellwords'
|
3
|
+
|
4
|
+
class Iostat
|
5
|
+
attr_reader :w_await, :r_await, :util, :disk_name
|
6
|
+
def initialize(path)
|
7
|
+
@path = path
|
8
|
+
@w_await = 0
|
9
|
+
@r_await = 0
|
10
|
+
@util = 0
|
11
|
+
@disk_name = 'unknown'
|
12
|
+
run
|
13
|
+
end
|
14
|
+
|
15
|
+
def run
|
16
|
+
@run = true
|
17
|
+
Thread.new do
|
18
|
+
disk_await_monitor
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def stop
|
23
|
+
@run = false
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def disk_await_monitor
|
29
|
+
drive = `df #{@path.shellescape}`.split("\n")[1].split(' ')[0].split('/').last
|
30
|
+
Open3.popen3('iostat -x 1 -p') do |_, stderr, _, thread|
|
31
|
+
while line = stderr.gets
|
32
|
+
update_stats(line) if line.split(' ')[0] == drive
|
33
|
+
unless @run
|
34
|
+
Process.kill('KILL', thread.pid) rescue nil
|
35
|
+
break
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def update_stats(line)
|
42
|
+
parts = line.gsub(/\s+/, ' ').split(' ')
|
43
|
+
@disk_name = parts.first
|
44
|
+
@util = parts.last.to_f
|
45
|
+
@w_await = parts[parts.size - 2].to_f
|
46
|
+
@r_await = parts[parts.size - 3].to_f
|
47
|
+
end
|
48
|
+
end
|
data/lib/manage.rb
CHANGED
@@ -0,0 +1,53 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require 'shellwords'
|
3
|
+
|
4
|
+
def autosync_list
|
5
|
+
FC::Var.get_autosync.each do |name, val|
|
6
|
+
puts name.to_s+(val.to_i > 0 ? " - every: #{val} seconds" : " - never")
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
def autosync_add
|
11
|
+
hosts = ['all'] + all_hosts
|
12
|
+
puts 'Set autosync interval'
|
13
|
+
begin
|
14
|
+
host = stdin_read_val("Host (default #{FC::Storage.curr_host})", true).strip
|
15
|
+
host = FC::Storage.curr_host if host.empty?
|
16
|
+
puts "Host can be one of: #{hosts.join(', ')}" unless hosts.index(host)
|
17
|
+
end until hosts.index(host)
|
18
|
+
interval = stdin_read_val('Autosync interval, seconds (0 - never, empty = all)', true)
|
19
|
+
confirm_autosync_set(host, interval)
|
20
|
+
end
|
21
|
+
|
22
|
+
def autosync_change
|
23
|
+
return if (host = find_host).to_s.empty?
|
24
|
+
puts "Change autosync interval for host #{host}"
|
25
|
+
interval = FC::Var.get_autosync[host]
|
26
|
+
txt = interval.to_s.empty? ? 'default (=all)' : nil
|
27
|
+
txt = interval.to_i.zero? ? 'never' : "#{interval}" unless txt
|
28
|
+
interval = stdin_read_val("Autosync interval, seconds (now #{txt}, 0 - never, empty = all)", true)
|
29
|
+
confirm_autosync_set(host, interval)
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
def confirm_autosync_set(host, interval)
|
35
|
+
txt = interval.to_s.empty? ? 'default (=all)' : nil
|
36
|
+
txt = interval.to_i.zero? ? 'never' : interval unless txt
|
37
|
+
puts %(\nAutosync interval
|
38
|
+
Host: #{host}
|
39
|
+
Interval: #{txt})
|
40
|
+
s = Readline.readline('Continue? (y/n) ', false).strip.downcase
|
41
|
+
puts ''
|
42
|
+
if %w[y yes].include?(s)
|
43
|
+
begin
|
44
|
+
FC::Var.set_autosync(host, interval.to_s.empty? ? interval : interval.to_i)
|
45
|
+
rescue Exception => e
|
46
|
+
puts "Error: #{e.message}"
|
47
|
+
exit
|
48
|
+
end
|
49
|
+
puts 'ok'
|
50
|
+
else
|
51
|
+
puts 'Canceled.'
|
52
|
+
end
|
53
|
+
end
|
data/lib/manage/copy_speed.rb
CHANGED
data/lib/manage/storages.rb
CHANGED
@@ -203,6 +203,53 @@ def storages_change
|
|
203
203
|
end
|
204
204
|
|
205
205
|
def storages_sync_info
|
206
|
+
if storage = find_storage
|
207
|
+
return puts "Storage #{storage.name} is not local." if storage.host != FC::Storage.curr_host
|
208
|
+
puts "Get synchronization info for (#{storage.name}) storage and file system (#{storage.path}).."
|
209
|
+
init_console_logger
|
210
|
+
manual_sync(storage, true)
|
211
|
+
puts 'Done.'
|
212
|
+
end
|
213
|
+
end
|
214
|
+
|
215
|
+
def storages_sync
|
216
|
+
if storage = find_storage
|
217
|
+
return puts "Storage #{storage.name} is not local." if storage.host != FC::Storage.curr_host
|
218
|
+
puts "Synchronize (#{storage.name}) storage and file system (#{storage.path}).."
|
219
|
+
s = Readline.readline('Continue? (y/n) ', false).strip.downcase
|
220
|
+
puts ''
|
221
|
+
if s == 'y' || s == 'yes'
|
222
|
+
init_console_logger
|
223
|
+
manual_sync(storage, false)
|
224
|
+
s = Readline.readline('Update storage size? (y/n) ', false).strip.downcase
|
225
|
+
storages_update_size if s == 'y' || s == 'yes'
|
226
|
+
else
|
227
|
+
puts "Canceled."
|
228
|
+
end
|
229
|
+
end
|
230
|
+
end
|
231
|
+
|
232
|
+
def manual_sync(storage, dry_run)
|
233
|
+
syncer = Autosync.new(storage, dry_run)
|
234
|
+
syncer.run
|
235
|
+
puts "Deleted #{syncer.files_to_delete.size} files"
|
236
|
+
puts "Deleted #{syncer.items_to_delete.size} items_storages"
|
237
|
+
if (ARGV[3])
|
238
|
+
File.open(ARGV[3], 'w') do |file|
|
239
|
+
syncer.files_to_delete.each { |f| file.puts f }
|
240
|
+
end
|
241
|
+
puts "Save deleted files to #{ARGV[3]}"
|
242
|
+
end
|
243
|
+
|
244
|
+
if (ARGV[4])
|
245
|
+
File.open(ARGV[4], 'w') do |file|
|
246
|
+
syncer.items_to_delete.each { |item_storage_id| file.puts item_storage_id }
|
247
|
+
end
|
248
|
+
puts "Save deleted items_storages to #{ARGV[4]}"
|
249
|
+
end
|
250
|
+
end
|
251
|
+
|
252
|
+
def storages_sync_info_old
|
206
253
|
if storage = find_storage
|
207
254
|
return puts "Storage #{storage.name} is not local." if storage.host != FC::Storage.curr_host
|
208
255
|
puts "Get synchronization info for (#{storage.name}) storage and file system (#{storage.path}).."
|
@@ -211,7 +258,7 @@ def storages_sync_info
|
|
211
258
|
end
|
212
259
|
end
|
213
260
|
|
214
|
-
def
|
261
|
+
def storages_sync_old
|
215
262
|
if storage = find_storage
|
216
263
|
return puts "Storage #{storage.name} is not local." if storage.host != FC::Storage.curr_host
|
217
264
|
puts "Synchronize (#{storage.name}) storage and file system (#{storage.path}).."
|
@@ -230,6 +277,15 @@ end
|
|
230
277
|
|
231
278
|
private
|
232
279
|
|
280
|
+
def init_console_logger
|
281
|
+
require 'logger'
|
282
|
+
$log = Logger.new(STDOUT)
|
283
|
+
$log.level = Logger::DEBUG
|
284
|
+
$log.formatter = proc { |severity, datetime, progname, msg|
|
285
|
+
"[#{severity}]: #{msg}\n"
|
286
|
+
}
|
287
|
+
end
|
288
|
+
|
233
289
|
def find_storage
|
234
290
|
name = ARGV[2]
|
235
291
|
storage = FC::Storage.where('name = ?', name).first
|
@@ -0,0 +1,186 @@
|
|
1
|
+
require 'helper'
|
2
|
+
require 'autosync'
|
3
|
+
|
4
|
+
class AutosyncTest < Test::Unit::TestCase
|
5
|
+
class << self
|
6
|
+
def startup
|
7
|
+
@@storage = FC::Storage.new(
|
8
|
+
name: 'rec1-sda',
|
9
|
+
host: 'rec1',
|
10
|
+
size: 0,
|
11
|
+
copy_storages: '',
|
12
|
+
size_limit: 10,
|
13
|
+
path: '/tmp/rec-1-sda/mediaroot/'
|
14
|
+
)
|
15
|
+
`mkdir -p #{@@storage.path}`
|
16
|
+
`touch #{@@storage.path}healthcheck`
|
17
|
+
`touch -t 9901010000 #{@@storage.path}healthcheck`
|
18
|
+
@@storage.save
|
19
|
+
end
|
20
|
+
|
21
|
+
def shutdown
|
22
|
+
FC::DB.query("DELETE FROM policies")
|
23
|
+
FC::DB.query("DELETE FROM items_storages")
|
24
|
+
FC::DB.query("DELETE FROM items")
|
25
|
+
FC::DB.query("DELETE FROM storages")
|
26
|
+
FC::DB.query("DELETE FROM errors")
|
27
|
+
`rm -rf #{@@storage.path}` if @@storage.path
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def setup
|
32
|
+
@item_storages = {}
|
33
|
+
[
|
34
|
+
'live_hls/otr_1/01/a.ts',
|
35
|
+
'live_hls/otr_1/01/b.ts',
|
36
|
+
'live_hls/otr_1/02/c.ts'
|
37
|
+
].each { |i| @item_storages[i] = create_item_storage(i) }
|
38
|
+
end
|
39
|
+
|
40
|
+
def teardown
|
41
|
+
FC::DB.query("DELETE FROM items_storages")
|
42
|
+
FC::DB.query("DELETE FROM items")
|
43
|
+
FC::DB.query("DELETE FROM errors")
|
44
|
+
`rm -rf #{@@storage.path}` if @@storage.path
|
45
|
+
end
|
46
|
+
|
47
|
+
should "fill_db with items on storage" do
|
48
|
+
as = Autosync.new(@@storage)
|
49
|
+
db_struct = as.fill_db
|
50
|
+
assert db_struct['live_hls']
|
51
|
+
assert db_struct['live_hls']['otr_1']
|
52
|
+
assert db_struct['live_hls']['otr_1']['01']
|
53
|
+
assert db_struct['live_hls']['otr_1']['01']['a.ts']
|
54
|
+
assert db_struct['live_hls']['otr_1']['01']['b.ts']
|
55
|
+
assert db_struct['live_hls']['otr_1']['02']
|
56
|
+
assert db_struct['live_hls']['otr_1']['02']['c.ts']
|
57
|
+
end
|
58
|
+
|
59
|
+
should "content synchonized, nothing to delete from DISK and DB" do
|
60
|
+
as = Autosync.new(@@storage)
|
61
|
+
db_struct = as.fill_db
|
62
|
+
as.scan_disk(db_struct, '')
|
63
|
+
assert as.files_to_delete.empty?
|
64
|
+
as.scan_db(db_struct, '')
|
65
|
+
assert as.items_to_delete.empty?
|
66
|
+
end
|
67
|
+
|
68
|
+
should 'select to remove disk file entry unless found in DB' do
|
69
|
+
as = Autosync.new(@@storage)
|
70
|
+
db_struct = as.fill_db
|
71
|
+
unstored_file = "#{@@storage.path}live_hls/otr_1/01/z.ts"
|
72
|
+
`touch -t 9901010000 #{unstored_file}`
|
73
|
+
as.scan_disk(db_struct, '')
|
74
|
+
assert as.files_to_delete.size == 1
|
75
|
+
assert as.files_to_delete.first == unstored_file
|
76
|
+
end
|
77
|
+
|
78
|
+
should 'physically remove disk entries older than 1 hour unless found in DB' do
|
79
|
+
`mkdir -p #{@@storage.path}live_hls/empty_subfolders/sub1/sub2`
|
80
|
+
`touch -t 9901010000 #{@@storage.path}live_hls/empty_subfolders`
|
81
|
+
`touch -t 9901010000 #{@@storage.path}live_hls/empty_subfolders/sub1`
|
82
|
+
`touch -t 9901010000 #{@@storage.path}live_hls/empty_subfolders/sub1/sub2`
|
83
|
+
assert File.exist?("#{@@storage.path}live_hls/empty_subfolders")
|
84
|
+
|
85
|
+
`mkdir -p #{@@storage.path}live_hls/not_empty_subfolders/sub1/sub2`
|
86
|
+
`touch -t 9901010000 #{@@storage.path}live_hls/not_empty_subfolders`
|
87
|
+
`touch -t 9901010000 #{@@storage.path}live_hls/not_empty_subfolders/sub1`
|
88
|
+
assert File.exist?("#{@@storage.path}live_hls/not_empty_subfolders/sub1/sub2")
|
89
|
+
|
90
|
+
`touch -t 9901010000 #{@@storage.path}live_hls/not_empty_subfolders/sub1/sub2/some_file`
|
91
|
+
assert File.exist?("#{@@storage.path}live_hls/not_empty_subfolders/sub1/sub2/some_file")
|
92
|
+
`touch -t 9901010000 #{@@storage.path}live_hls/not_empty_subfolders/sub1/sub2`
|
93
|
+
|
94
|
+
`mkdir -p #{@@storage.path}live_hls/new_empty_folders/sub1/sub2`
|
95
|
+
|
96
|
+
as = Autosync.new(@@storage)
|
97
|
+
db_struct = as.fill_db
|
98
|
+
as.scan_disk(db_struct, '')
|
99
|
+
assert as.files_to_delete.size == 2
|
100
|
+
as.delete_diffs
|
101
|
+
assert !File.exist?("#{@@storage.path}live_hls/empty_subfolders")
|
102
|
+
assert !File.exist?("#{@@storage.path}live_hls/not_empty_subfolders")
|
103
|
+
assert File.exist?("#{@@storage.path}live_hls/new_empty_folders/sub1/sub2")
|
104
|
+
end
|
105
|
+
|
106
|
+
should 'not remove folder from disk if some file appeared between disk scan and delete process' do
|
107
|
+
# make old empty folder
|
108
|
+
`mkdir -p #{@@storage.path}live_hls/empty_subfolders/sub1/sub2`
|
109
|
+
`touch -t 9901010000 #{@@storage.path}live_hls/empty_subfolders`
|
110
|
+
`touch -t 9901010000 #{@@storage.path}live_hls/empty_subfolders/sub1`
|
111
|
+
`touch -t 9901010000 #{@@storage.path}live_hls/empty_subfolders/sub1/sub2`
|
112
|
+
assert File.exist?("#{@@storage.path}live_hls/empty_subfolders")
|
113
|
+
|
114
|
+
as = Autosync.new(@@storage)
|
115
|
+
db_struct = as.fill_db
|
116
|
+
# scan disk
|
117
|
+
as.scan_disk(db_struct, '')
|
118
|
+
assert as.files_to_delete.size == 1
|
119
|
+
assert as.files_to_delete[0] == "#{@@storage.path}live_hls/empty_subfolders"
|
120
|
+
# new file
|
121
|
+
`touch #{@@storage.path}live_hls/empty_subfolders/sub1/sub2/new_appeared_file`
|
122
|
+
as.delete_diffs
|
123
|
+
assert File.exist?("#{@@storage.path}live_hls/empty_subfolders/sub1/sub2/new_appeared_file")
|
124
|
+
end
|
125
|
+
|
126
|
+
should 'select for delete file with mtime less than 1 hour' do
|
127
|
+
old_file = "#{@@storage.path}live_hls/otr_1/01/old.ts"
|
128
|
+
new_file = "#{@@storage.path}live_hls/otr_1/01/new.ts"
|
129
|
+
`touch -t #{(Time.now - 3601).strftime('%Y%m%d%H%M.%S')} #{old_file}`
|
130
|
+
`touch -t #{(Time.now - 3509).strftime('%Y%m%d%H%M.%S')} #{new_file}`
|
131
|
+
as = Autosync.new(@@storage)
|
132
|
+
db_struct = as.fill_db
|
133
|
+
as.scan_disk(db_struct, '')
|
134
|
+
assert as.files_to_delete.size == 1
|
135
|
+
assert as.files_to_delete.first == old_file
|
136
|
+
end
|
137
|
+
|
138
|
+
should 'not select for delete disk folder with entries which is in db' do
|
139
|
+
`mkdir -p #{@@storage.path}track/01`
|
140
|
+
create_item_storage('track/01')
|
141
|
+
# make it all old
|
142
|
+
`touch -t 9901010000 #{@@storage.path}track`
|
143
|
+
`touch -t 9901010000 #{@@storage.path}track/01`
|
144
|
+
# make some old files
|
145
|
+
`touch -t 9901010000 #{@@storage.path}track/01/s-0001.ts`
|
146
|
+
`touch -t 9901010000 #{@@storage.path}track/01/s-0002.ts`
|
147
|
+
`touch -t 9901010000 #{@@storage.path}track/01/s-0003.ts`
|
148
|
+
as = Autosync.new(@@storage)
|
149
|
+
db_struct = as.fill_db
|
150
|
+
as.scan_disk(db_struct, '')
|
151
|
+
assert as.files_to_delete.size.zero?
|
152
|
+
end
|
153
|
+
|
154
|
+
should 'select and remove DB item if not exist on disk' do
|
155
|
+
item_name = @item_storages.keys.first
|
156
|
+
`rm -f #{@@storage.path}#{item_name}`
|
157
|
+
removed_item_storage_id = @item_storages[item_name].id
|
158
|
+
as = Autosync.new(@@storage)
|
159
|
+
db_struct = as.fill_db
|
160
|
+
as.scan_disk(db_struct, '')
|
161
|
+
assert as.files_to_delete.empty?
|
162
|
+
as.scan_db(db_struct, '')
|
163
|
+
assert as.items_to_delete.size == 1
|
164
|
+
assert as.items_to_delete[0] == removed_item_storage_id
|
165
|
+
as.delete_diffs
|
166
|
+
@item_storages[item_name].reload
|
167
|
+
assert @item_storages[item_name].status == 'error'
|
168
|
+
assert FC::Error.where('1').to_a.size == 1
|
169
|
+
end
|
170
|
+
|
171
|
+
def create_item_storage(item_name)
|
172
|
+
item = FC::Item.new
|
173
|
+
item.name = item_name
|
174
|
+
item.size = 0
|
175
|
+
item.save
|
176
|
+
item_storage = FC::ItemStorage.new
|
177
|
+
item_storage.item_id = item.id
|
178
|
+
item_storage.storage_name = @@storage.name
|
179
|
+
item_storage.status = 'ready'
|
180
|
+
item_storage.save
|
181
|
+
`mkdir -p #{@@storage.path}#{File.dirname(item_name)}`
|
182
|
+
`touch -t 9901010000 #{@@storage.path}#{item_name}`
|
183
|
+
item_storage
|
184
|
+
end
|
185
|
+
|
186
|
+
end
|