filecluster 0.3.0 → 0.3.1

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -40,12 +40,14 @@ Selecting available storage to copy item by storage.copy_storages (from left to
40
40
  |global_daemon_host||set fc_daemon when run global daemon task (only in one instance)|
41
41
  |daemon_cycle_time|30|time between global daemon checks and storages available checks|
42
42
  |daemon_global_wait_time|120|time between runs global daemon if it does not running|
43
- |daemon_global_tasks_group_limit|1000|limit for select for tasks|
43
+ |daemon_tasks_copy_group_limit|1000|select limit for copy tasks|
44
+ |daemon_tasks_delete_group_limit|10000|select limit for delete tasks|
45
+ |daemon_tasks_copy_threads_limit|10|copy tasks threads count limit for one storage|
46
+ |daemon_tasks_delete_threads_limit|10|delete tasks threads count limit for one storage|
47
+ |daemon_copy_tasks_per_host_limit|10|copy tasks count limit for one host|
48
+ |daemon_global_tasks_group_limit|1000|select limit for create copy tasks|
44
49
  |daemon_global_error_items_ttl|86400|ttl for items with error status before delete|
45
50
  |daemon_global_error_items_storages_ttl|86400|ttl for items_storages with error status before delete|
46
- |daemon_global_tasks_per_thread|10|tasks count for one task thread|
47
- |daemon_global_tasks_threads_limit|10|tasks threads count limit for one storage|
48
- |daemon_copy_tasks_limit|10|copy tasks count limit for one host|
49
51
  |daemon_restart_period|86400|time between fc-daemon self restart|
50
52
 
51
53
  ## Usage
@@ -8,16 +8,19 @@ require 'filecluster'
8
8
  require 'utils'
9
9
  require 'daemon'
10
10
 
11
- $storages = [] # storages on current host
12
- $tasks = {} # tasks by storage name
13
- $curr_tasks = [] # current tasks
14
- $tasks_threads = {} # threads by storage name
15
- $check_threads = {} # threads by storage name
16
- $copy_count = 0 # copy tasks count
17
- $exit_signal = false
11
+ $all_storages = [] # all storages
12
+ $storages = [] # storages on current host
13
+ $tasks_copy = {} # copy tasks by storage name
14
+ $tasks_delete = {} # delete tasks by storage name
15
+ $curr_tasks = [] # current tasks
16
+ $tasks_copy_threads = {} # copy threads by storage name
17
+ $tasks_delete_threads = {} # delete threads by storage name
18
+ $check_threads = {} # check threads by storage name
19
+ $copy_count = 0 # copy tasks count for current host
20
+ $exit_signal = false
18
21
  $global_daemon_thread = nil
19
- $update_tasks_thread = nil
20
- $run_tasks_thread = nil
22
+ $update_tasks_thread = nil
23
+ $run_tasks_thread = nil
21
24
 
22
25
  default_db_config = File.expand_path(File.dirname(__FILE__))+'/db.yml'
23
26
  descriptions = {
@@ -4,7 +4,8 @@ require "daemon/check_thread"
4
4
  require "daemon/global_daemon_thread"
5
5
  require "daemon/run_tasks_thread"
6
6
  require "daemon/update_tasks_thread"
7
- require "daemon/task_thread"
7
+ require "daemon/copy_task_thread"
8
+ require "daemon/delete_task_thread"
8
9
 
9
10
  def error(msg, options = {})
10
11
  $log.error(msg)
@@ -0,0 +1,45 @@
1
+ class CopyTaskThread < BaseThread
2
+ def go(storage_name)
3
+ return unless $tasks_copy[storage_name]
4
+ Thread.current[:tasks_processed] = 0 unless Thread.current[:tasks_processed]
5
+ while task = $tasks_copy[storage_name].shift do
6
+ $curr_tasks << task
7
+ $log.debug("CopyTaskThread(#{storage_name}): run task for item_storage ##{task.id}")
8
+ make_copy(task)
9
+ $curr_tasks.delete(task)
10
+ $log.debug("CopyTaskThread(#{storage_name}): finish task for item_storage ##{task.id}")
11
+ Thread.current[:tasks_processed] += 1
12
+ exit if $exit_signal
13
+ end
14
+ end
15
+
16
+ def make_copy(task)
17
+ sleep 0.1 while $copy_count > FC::Var.get('daemon_copy_tasks_per_host_limit', 10).to_i
18
+ $copy_count += 1
19
+ storage = $storages.detect{|s| s.name == task.storage_name}
20
+ begin
21
+ item = FC::Item.find(task.item_id)
22
+ rescue Exception => e
23
+ if e.message.match('Record not found')
24
+ $log.warn("Item ##{task.item_id} not found before copy")
25
+ return nil
26
+ else
27
+ raise e
28
+ end
29
+ end
30
+ return nil unless item && item.status == 'ready'
31
+ src_item_storage = FC::ItemStorage.where("item_id = ? AND status = 'ready'", item.id).sample
32
+ unless src_item_storage
33
+ $log.warn("Item ##{item.id} #{item.name} has no ready item_storage")
34
+ return nil
35
+ end
36
+ src_storage = $all_storages.detect{|s| s.name == src_item_storage.storage_name}
37
+ $log.debug("Copy from #{src_storage.name} to #{storage.name} #{storage.path}#{item.name}")
38
+ item.copy_item_storage(src_storage, storage, task)
39
+ rescue Exception => e
40
+ error "Copy item_storage error: #{e.message}; #{e.backtrace.join(', ')}", :item_id => task.item_id, :item_storage_id => task.id
41
+ $curr_tasks.delete(task)
42
+ ensure
43
+ $copy_count -= 1 if $copy_count > 0
44
+ end
45
+ end
@@ -0,0 +1,35 @@
1
+ class DeleteTaskThread < BaseThread
2
+ def go(storage_name)
3
+ return unless $tasks_delete[storage_name]
4
+ Thread.current[:tasks_processed] = 0 unless Thread.current[:tasks_processed]
5
+ while task = $tasks_delete[storage_name].shift do
6
+ $curr_tasks << task
7
+ $log.debug("DeleteTaskThread(#{storage_name}): run task for item_storage ##{task.id}")
8
+ make_delete(task)
9
+ $curr_tasks.delete(task)
10
+ $log.debug("DeleteTaskThread(#{storage_name}): finish task for item_storage ##{task.id}")
11
+ Thread.current[:tasks_processed] += 1
12
+ exit if $exit_signal
13
+ end
14
+ end
15
+
16
+ def make_delete(task)
17
+ storage = $storages.detect{|s| s.name == task.storage_name}
18
+ begin
19
+ item = FC::Item.find(task.item_id)
20
+ rescue Exception => e
21
+ if e.message.match('Record not found')
22
+ $log.warn("Item ##{task.item_id} not found before delete")
23
+ return nil
24
+ else
25
+ raise e
26
+ end
27
+ end
28
+ $log.debug("Delete #{storage.path}#{item.name}")
29
+ storage.delete_file(item.name)
30
+ task.delete
31
+ rescue Exception => e
32
+ error "Delete item_storage error: #{e.message}; #{e.backtrace.join(', ')}", :item_id => task.item_id, :item_storage_id => task.id
33
+ $curr_tasks.delete(task)
34
+ end
35
+ end
@@ -1,24 +1,32 @@
1
1
  class RunTasksThread < BaseThread
2
2
  def go
3
- $log.debug("Run tasks (copy_count: #{$copy_count})")
3
+ $log.debug('Run tasks')
4
+ run_tasks(:delete)
5
+ run_tasks(:copy)
6
+ end
7
+
8
+ def run_tasks(type)
9
+ tasks = (type == :copy ? $tasks_copy : $tasks_delete)
10
+ tasks_threads = (type == :copy ? $tasks_copy_threads : $tasks_delete_threads)
4
11
  $storages.each do |storage|
5
- $tasks_threads[storage.name] = [] unless $tasks_threads[storage.name]
6
- $tasks_threads[storage.name].delete_if {|thread| !thread.alive?}
7
- tasks_count = $tasks[storage.name] ? $tasks[storage.name].size : 0
8
- threads_count = $tasks_threads[storage.name].count
9
-
10
- # <max_threads> tasks per thread, maximum <tasks_per_thread> threads
11
- max_threads = FC::Var.get('daemon_global_tasks_threads_limit', 10).to_i
12
- tasks_per_thread = FC::Var.get('daemon_global_tasks_per_thread', 10).to_i
12
+ tasks_threads[storage.name] = [] unless tasks_threads[storage.name]
13
+ tasks_threads[storage.name].delete_if {|thread| !thread.alive?}
14
+ tasks_count = tasks[storage.name] ? tasks[storage.name].size : 0
15
+ threads_count = tasks_threads[storage.name].count
16
+ thread_avg_performance = 0
17
+ thread_avg_performance = tasks_threads[storage.name].inject(0){|sum, thread| sum+thread[:tasks_processed]} / threads_count if threads_count > 0
18
+ thread_avg_performance = 10 if thread_avg_performance < 10
19
+ max_threads = FC::Var.get("daemon_tasks_#{type}_threads_limit", 10).to_i
13
20
 
14
- run_threads_count = (tasks_count/tasks_per_thread.to_f).ceil
21
+ run_threads_count = (tasks_count/thread_avg_performance.to_f).ceil
15
22
  run_threads_count = max_threads if run_threads_count > max_threads
16
23
  run_threads_count = run_threads_count - threads_count
24
+ run_threads_count = 0 if run_threads_count < 0
17
25
 
18
- $log.debug("tasks_count: #{tasks_count}, threads_count: #{threads_count}, run_threads_count: #{run_threads_count}")
26
+ $log.debug("#{storage.name} #{type} tasks_count: #{tasks_count}, threads_count: #{threads_count}, avg_performance: #{thread_avg_performance}, run_threads_count: #{run_threads_count}")
27
+ tasks_threads[storage.name].each{|thread| thread[:tasks_processed] = 0}
19
28
  run_threads_count.times do
20
- $log.debug("spawn TaskThread for #{storage.name}")
21
- $tasks_threads[storage.name] << TaskThread.new(storage.name)
29
+ tasks_threads[storage.name] << (type == :copy ? CopyTaskThread.new(storage.name) : DeleteTaskThread.new(storage.name))
22
30
  end
23
31
  end
24
32
  end
@@ -6,22 +6,21 @@ class UpdateTasksThread < BaseThread
6
6
  end
7
7
 
8
8
  def check_tasks(type)
9
- storages_names = $storages.map{|storage| "'#{storage.name}'"}.join(',')
10
- return if storages_names.empty?
11
- cond = "storage_name in (#{storages_names}) AND status='#{type.to_s}'"
12
- ids = $tasks.map{|storage_name, storage_tasks| storage_tasks.select{|task| task[:action] == type}}.
13
- flatten.map{|task| task[:item_storage].id}
14
- ids += $curr_tasks.select{|task| task[:action] == type}.map{|task| task[:item_storage].id}
15
-
16
- limit = FC::Var.get('daemon_global_tasks_group_limit', 1000).to_i
17
- cond << "AND id not in (#{ids.join(',')})" if (ids.length > 0)
18
- cond << " LIMIT #{limit}"
19
- FC::ItemStorage.where(cond).each do |item_storage|
20
- unless ids.include?(item_storage.id)
21
- $tasks[item_storage.storage_name] = [] unless $tasks[item_storage.storage_name]
22
- $tasks[item_storage.storage_name] << {:action => type, :item_storage => item_storage}
9
+ count = 0
10
+ tasks = (type == :copy ? $tasks_copy : $tasks_delete)
11
+ $storages.each do |storage|
12
+ tasks[storage.name] = [] unless tasks[storage.name]
13
+ cond = "storage_name = '#{storage.name}' AND status='#{type.to_s}'"
14
+ ids = tasks[storage.name].map(&:id) + $curr_tasks.map(&:id)
15
+ limit = FC::Var.get("daemon_tasks_#{type}_group_limit", 1000).to_i
16
+ cond << "AND id not in (#{ids.join(',')})" if ids.length > 0
17
+ cond << " LIMIT #{limit}"
18
+ FC::ItemStorage.where(cond).each do |item_storage|
19
+ tasks[storage.name] << item_storage
23
20
  $log.debug("task add: type=#{type}, item_storage=#{item_storage.id}")
21
+ count +=1
24
22
  end
25
23
  end
24
+ $log.debug("Add #{count} #{type} tasks")
26
25
  end
27
26
  end
@@ -191,12 +191,14 @@ module FC
191
191
  FC::DB.connect.query("CREATE TRIGGER fc_vars_before_update BEFORE UPDATE on #{@prefix}vars FOR EACH ROW BEGIN #{proc_time} END")
192
192
  FC::DB.connect.query("INSERT INTO #{@prefix}vars SET name='daemon_cycle_time', val='30', descr='time between global daemon checks and storages available checks'")
193
193
  FC::DB.connect.query("INSERT INTO #{@prefix}vars SET name='daemon_global_wait_time', val='120', descr='time between runs global daemon if it does not running'")
194
- FC::DB.connect.query("INSERT INTO #{@prefix}vars SET name='daemon_global_tasks_group_limit', val='1000', descr='limit for select for tasks'")
194
+ FC::DB.connect.query("INSERT INTO #{@prefix}vars SET name='daemon_tasks_copy_group_limit', val='1000', descr='select limit for copy tasks'")
195
+ FC::DB.connect.query("INSERT INTO #{@prefix}vars SET name='daemon_tasks_delete_group_limit', val='10000', descr='select limit for delete tasks'")
196
+ FC::DB.connect.query("INSERT INTO #{@prefix}vars SET name='daemon_tasks_copy_threads_limit', val='10', descr='copy tasks threads count limit for one storage'")
197
+ FC::DB.connect.query("INSERT INTO #{@prefix}vars SET name='daemon_tasks_delete_threads_limit', val='10', descr='delete tasks threads count limit for one storage'")
198
+ FC::DB.connect.query("INSERT INTO #{@prefix}vars SET name='daemon_copy_tasks_per_host_limit', val='10', descr='copy tasks count limit for one host'")
199
+ FC::DB.connect.query("INSERT INTO #{@prefix}vars SET name='daemon_global_tasks_group_limit', val='1000', descr='select limit for create copy tasks'")
195
200
  FC::DB.connect.query("INSERT INTO #{@prefix}vars SET name='daemon_global_error_items_ttl', val='86400', descr='ttl for items with error status before delete'")
196
201
  FC::DB.connect.query("INSERT INTO #{@prefix}vars SET name='daemon_global_error_items_storages_ttl', val='86400', descr='ttl for items_storages with error status before delete'")
197
- FC::DB.connect.query("INSERT INTO #{@prefix}vars SET name='daemon_global_tasks_per_thread', val='10', descr='tasks count for one task thread'")
198
- FC::DB.connect.query("INSERT INTO #{@prefix}vars SET name='daemon_global_tasks_threads_limit', val='10', descr='tasks threads count limit for one storage'")
199
- FC::DB.connect.query("INSERT INTO #{@prefix}vars SET name='daemon_copy_tasks_limit', val='10', descr='copy tasks count limit for one host'")
200
202
  FC::DB.connect.query("INSERT INTO #{@prefix}vars SET name='daemon_restart_period', val='86400', descr='time between fc-daemon self restart'")
201
203
  end
202
204
  end
@@ -1,3 +1,3 @@
1
1
  module FC
2
- VERSION = "0.3.0"
2
+ VERSION = "0.3.1"
3
3
  end
@@ -128,7 +128,7 @@ def storages_change
128
128
  storage.url = url unless url.empty?
129
129
  storage.size_limit = human_to_size(size_limit) unless size_limit.empty?
130
130
  storages = FC::Storage.where.map(&:name)
131
- copy_storages = copy_storages.split(',').select{|s| storages.member?(s.strip)}.join(',').strip unless copy_storages.empty?
131
+ storage.copy_storages = copy_storages.split(',').select{|s| storages.member?(s.strip)}.join(',').strip unless copy_storages.empty?
132
132
 
133
133
  puts %Q{\nStorage
134
134
  Name: #{storage.name}
@@ -137,7 +137,7 @@ def storages_change
137
137
  Url: #{storage.url}
138
138
  Size: #{size_to_human storage.size}
139
139
  Size limit: #{size_to_human storage.size_limit}
140
- Copy storages: #{copy_storages}}
140
+ Copy storages: #{storage.copy_storages}}
141
141
  s = Readline.readline("Continue? (y/n) ", false).strip.downcase
142
142
  puts ""
143
143
  if s == "y" || s == "yes"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: filecluster
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.3.1
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-11-11 00:00:00.000000000 Z
12
+ date: 2013-11-12 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rb-readline
@@ -146,9 +146,10 @@ files:
146
146
  - lib/daemon.rb
147
147
  - lib/daemon/base_thread.rb
148
148
  - lib/daemon/check_thread.rb
149
+ - lib/daemon/copy_task_thread.rb
150
+ - lib/daemon/delete_task_thread.rb
149
151
  - lib/daemon/global_daemon_thread.rb
150
152
  - lib/daemon/run_tasks_thread.rb
151
- - lib/daemon/task_thread.rb
152
153
  - lib/daemon/update_tasks_thread.rb
153
154
  - lib/fc/base.rb
154
155
  - lib/fc/db.rb
@@ -192,7 +193,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
192
193
  version: '0'
193
194
  segments:
194
195
  - 0
195
- hash: 2037414088552914900
196
+ hash: -4221257389535843985
196
197
  required_rubygems_version: !ruby/object:Gem::Requirement
197
198
  none: false
198
199
  requirements:
@@ -201,7 +202,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
201
202
  version: '0'
202
203
  segments:
203
204
  - 0
204
- hash: 2037414088552914900
205
+ hash: -4221257389535843985
205
206
  requirements: []
206
207
  rubyforge_project:
207
208
  rubygems_version: 1.8.24
@@ -1,53 +0,0 @@
1
- class TaskThread < BaseThread
2
- def go(storage_name)
3
- return unless $tasks[storage_name]
4
- while task = $tasks[storage_name].shift do
5
- $curr_tasks << task
6
- $log.debug("TaskThread(#{storage_name}): run task type=#{task[:action]}, item_storage=#{task[:item_storage].id}")
7
- if task[:action] == :delete
8
- make_delete(task)
9
- elsif task[:action] == :copy
10
- make_copy(task)
11
- else
12
- error "Unknown task action: #{task[:action]}"
13
- end
14
- $curr_tasks.delete(task)
15
- $log.debug("TaskThread(#{storage_name}): Finish task type=#{task[:action]}, item_storage=#{task[:item_storage].id}")
16
- exit if $exit_signal
17
- end
18
- end
19
-
20
- def make_delete(task)
21
- item_storage = task[:item_storage]
22
- storage = $storages.detect{|s| s.name == item_storage.storage_name}
23
- item = FC::Item.find(item_storage.item_id)
24
- $log.debug("Delete #{storage.path}#{item.name}")
25
- storage.delete_file(item.name)
26
- item_storage.delete
27
- rescue Exception => e
28
- error "Delete item_storage error: #{e.message}; #{e.backtrace.join(', ')}", :item_id => item_storage.item_id, :item_storage_id => item_storage.id
29
- $curr_tasks.delete(task)
30
- end
31
-
32
- def make_copy(task)
33
- sleep 0.1 while $copy_count > FC::Var.get('daemon_copy_tasks_limit', 10).to_i
34
- $copy_count += 1
35
- item_storage = task[:item_storage]
36
- storage = $storages.detect{|s| s.name == item_storage.storage_name}
37
- item = FC::Item.find(item_storage.item_id)
38
- return nil unless item && item.status == 'ready'
39
- src_item_storage = FC::ItemStorage.where("item_id = ? AND status = 'ready'", item.id).sample
40
- unless src_item_storage
41
- $log.info("Item ##{item.id} #{item.name} has no ready item_storage")
42
- return nil
43
- end
44
- src_storage = $all_storages.detect{|s| s.name == src_item_storage.storage_name}
45
- $log.debug("Copy from #{src_storage.name} to #{storage.name} #{storage.path}#{item.name}")
46
- item.copy_item_storage(src_storage, storage, item_storage)
47
- rescue Exception => e
48
- error "Copy item_storage error: #{e.message}; #{e.backtrace.join(', ')}", :item_id => item_storage.item_id, :item_storage_id => item_storage.id
49
- $curr_tasks.delete(task)
50
- ensure
51
- $copy_count -= 1 if item_storage && $copy_count > 0
52
- end
53
- end