filecluster 0.3.0 → 0.3.1

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/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