filecluster 0.1.6 → 0.1.7

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.
@@ -8,12 +8,12 @@ require 'filecluster'
8
8
  require 'utils'
9
9
  require 'daemon'
10
10
 
11
- $storages = []
12
- $tasks = {} # tasks by storage name
13
- $curr_task = {} # task by storage name
14
- $tasks_threads = {} # threads by storage name
15
- $check_threads = {} # threads by storage name
16
- $exit_signal = false
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
+ $exit_signal = false
17
17
  $global_daemon_thread = nil
18
18
 
19
19
  default_db_config = File.expand_path(File.dirname(__FILE__))+'/db.yml'
@@ -17,12 +17,12 @@ end
17
17
 
18
18
  def run_global_daemon(timeout)
19
19
  $log.debug('Run global daemon check')
20
- r = FC::DB.connect.query("SELECT #{FC::DB.prefix}vars.*, UNIX_TIMESTAMP() as curr_time FROM #{FC::DB.prefix}vars WHERE name='global_daemon_host'").first
20
+ r = FC::DB.query("SELECT #{FC::DB.prefix}vars.*, UNIX_TIMESTAMP() as curr_time FROM #{FC::DB.prefix}vars WHERE name='global_daemon_host'").first
21
21
  if !r || r['curr_time'].to_i - r['time'].to_i > timeout
22
22
  $log.debug('Set global daemon host to current')
23
- FC::DB.connect.query("REPLACE #{FC::DB.prefix}vars SET val='#{FC::Storage.curr_host}', name='global_daemon_host'")
23
+ FC::DB.query("REPLACE #{FC::DB.prefix}vars SET val='#{FC::Storage.curr_host}', name='global_daemon_host'")
24
24
  sleep 1
25
- r = FC::DB.connect.query("SELECT #{FC::DB.prefix}vars.*, UNIX_TIMESTAMP() as curr_time FROM #{FC::DB.prefix}vars WHERE name='global_daemon_host'").first
25
+ r = FC::DB.query("SELECT #{FC::DB.prefix}vars.*, UNIX_TIMESTAMP() as curr_time FROM #{FC::DB.prefix}vars WHERE name='global_daemon_host'").first
26
26
  end
27
27
  if r['val'] == FC::Storage.curr_host
28
28
  if !$global_daemon_thread || !$global_daemon_thread.alive?
@@ -66,9 +66,10 @@ def update_tasks
66
66
  cond = "storage_name in (#{storages_names}) AND status='#{type.to_s}'"
67
67
  ids = $tasks.map{|storage_name, storage_tasks| storage_tasks.select{|task| task[:action] == type}}.
68
68
  flatten.map{|task| task[:item_storage].id}
69
- $curr_task.map{|storage_name, task| ids << task[:item_storage].id if task && task[:action] == type}
69
+ ids += $curr_tasks.select{|task| task[:action] == type}
70
70
 
71
71
  cond << "AND id not in (#{ids.join(',')})" if (ids.length > 0)
72
+ cond << "LIMIT 1000"
72
73
  FC::ItemStorage.where(cond).each do |item_storage|
73
74
  $tasks[item_storage.storage_name] = [] unless $tasks[item_storage.storage_name]
74
75
  $tasks[item_storage.storage_name] << {:action => type, :item_storage => item_storage}
@@ -83,10 +84,17 @@ end
83
84
  def run_tasks
84
85
  $log.debug('Run tasks')
85
86
  $storages.each do |storage|
86
- thread = $tasks_threads[storage.name]
87
- if (!thread || !thread.alive?) && $tasks[storage.name] && $tasks[storage.name].size > 0
87
+ $tasks_threads[storage.name] = [] unless $tasks_threads[storage.name]
88
+ $tasks_threads[storage.name].delete_if {|thread| !thread.alive?}
89
+ tasks_count = $tasks[storage.name] ? $tasks[storage.name].size : 0
90
+ threads_count = $tasks_threads[storage.name].count
91
+ # 10 tasks per thread, maximum 3 tasks
92
+ run_threads_count = (tasks_count/10.0).ceil - threads_count
93
+ run_threads_count = 3 if run_threads_count > 3
94
+ $log.debug("tasks_count: #{tasks_count}, threads_count: #{threads_count}, run_threads_count: #{run_threads_count}")
95
+ run_threads_count.times do
88
96
  $log.debug("spawn TaskThread for #{storage.name}")
89
- $tasks_threads[storage.name] = TaskThread.new(storage.name)
97
+ $tasks_threads[storage.name] << TaskThread.new(storage.name)
90
98
  end
91
99
  end
92
100
  end
@@ -6,9 +6,9 @@ class GlobalDaemonThread < BaseThread
6
6
  sleep timeout.to_f/2
7
7
  exit if $exit_signal
8
8
 
9
- r = FC::DB.connect.query("SELECT #{FC::DB.prefix}vars.*, UNIX_TIMESTAMP() as curr_time FROM #{FC::DB.prefix}vars WHERE name='global_daemon_host'").first
9
+ r = FC::DB.query("SELECT #{FC::DB.prefix}vars.*, UNIX_TIMESTAMP() as curr_time FROM #{FC::DB.prefix}vars WHERE name='global_daemon_host'").first
10
10
  if r['val'] == FC::Storage.curr_host
11
- FC::DB.connect.query("UPDATE #{FC::DB.prefix}vars SET val='#{FC::Storage.curr_host}' WHERE name='global_daemon_host'")
11
+ FC::DB.query("UPDATE #{FC::DB.prefix}vars SET val='#{FC::Storage.curr_host}' WHERE name='global_daemon_host'")
12
12
  else
13
13
  $log.info("Exit from GlobalDaemonThread: global daemon already running on #{r['val']}")
14
14
  FC::DB.close
@@ -40,7 +40,7 @@ class GlobalDaemonThread < BaseThread
40
40
  sql = "SELECT i.id as item_id, i.size, i.copies as item_copies, GROUP_CONCAT(ist.storage_name ORDER BY ist.id) as storages, p.id as policy_id, p.copies as policy_copies "+
41
41
  "FROM #{FC::Item.table_name} as i, #{FC::Policy.table_name} as p, #{FC::ItemStorage.table_name} as ist WHERE "+
42
42
  "i.policy_id = p.id AND ist.item_id = i.id AND i.copies > 0 AND i.copies < p.copies AND i.status = 'ready' AND ist.status <> 'delete' GROUP BY i.id LIMIT 1000"
43
- r = FC::DB.connect.query(sql)
43
+ r = FC::DB.query(sql)
44
44
  r.each do |row|
45
45
  $log.info("GlobalDaemonThread: new item_storage for item #{row['item_id']}")
46
46
  item_storages = row['storages'].split(',')
@@ -61,11 +61,11 @@ class GlobalDaemonThread < BaseThread
61
61
  def delete_deleted_items
62
62
  $log.debug("GlobalDaemonThread: delete_deleted_items")
63
63
 
64
- r = FC::DB.connect.query("SELECT i.id FROM #{FC::Item.table_name} as i LEFT JOIN #{FC::ItemStorage.table_name} as ist ON i.id=ist.item_id WHERE i.status = 'delete' AND ist.id IS NULL")
64
+ r = FC::DB.query("SELECT i.id FROM #{FC::Item.table_name} as i LEFT JOIN #{FC::ItemStorage.table_name} as ist ON i.id=ist.item_id WHERE i.status = 'delete' AND ist.id IS NULL")
65
65
  ids = r.map{|row| row['id']}
66
66
  if ids.count > 0
67
67
  ids = ids.join(',')
68
- FC::DB.connect.query("DELETE FROM #{FC::Item.table_name} WHERE id in (#{ids})")
68
+ FC::DB.query("DELETE FROM #{FC::Item.table_name} WHERE id in (#{ids})")
69
69
  $log.info("GlobalDaemonThread: delete items #{ids}")
70
70
  end
71
71
  end
@@ -1,38 +1,48 @@
1
1
  class TaskThread < BaseThread
2
2
  def go(storage_name)
3
+ return unless $tasks[storage_name]
3
4
  while task = $tasks[storage_name].shift do
4
- $curr_task[storage_name] = task
5
+ $curr_tasks << task
5
6
  $log.debug("TaskThread(#{storage_name}): run task type=#{task[:action]}, item_storage=#{task[:item_storage].id}")
6
7
  if task[:action] == :delete
7
- make_delete(task[:item_storage])
8
+ make_delete(task)
8
9
  elsif task[:action] == :copy
9
- make_copy(task[:item_storage])
10
+ make_copy(task)
10
11
  else
11
12
  error "Unknown task action: #{task[:action]}"
12
13
  end
13
- $curr_task[storage_name] = nil
14
+ $curr_tasks.delete(task)
14
15
  $log.debug("TaskThread(#{storage_name}): Finish task type=#{task[:action]}, item_storage=#{task[:item_storage].id}")
15
16
  end
16
17
  end
17
18
 
18
- def make_delete(item_storage)
19
+ def make_delete(task)
20
+ item_storage = task[:item_storage]
21
+ # TODO: не лазить в базу за item
19
22
  storage = $storages.detect{|s| s.name == item_storage.storage_name}
20
23
  item = FC::Item.find(item_storage.item_id)
21
24
  storage.delete_file(item.name)
22
25
  item_storage.delete
23
26
  rescue Exception => e
24
27
  error "Delete item_storage error: #{e.message}; #{e.backtrace.join(', ')}", :item_id => item_storage.item_id, :item_storage_id => item_storage.id
28
+ $curr_tasks.delete(task)
25
29
  end
26
30
 
27
- def make_copy(item_storage)
31
+ def make_copy(task)
32
+ item_storage = task[:item_storage]
28
33
  # TODO: не лазить в базу за item, item_storages - перенести на стадию подготовки task-а
29
34
  storage = $storages.detect{|s| s.name == item_storage.storage_name}
30
35
  item = FC::Item.find(item_storage.item_id)
31
36
  src_item_storage = FC::ItemStorage.where("item_id = ? AND status = 'ready'", item.id).sample
37
+ unless src_item_storage
38
+ $log.info("Item ##{item.id} #{item.name} has no ready item_storage")
39
+ return nil
40
+ end
32
41
  src_storage = $all_storages.detect{|s| s.name == src_item_storage.storage_name}
33
42
  $log.debug("Copy from #{src_storage.name} to #{storage.name} #{storage.path}#{item.name}")
34
43
  item.copy_item_storage(src_storage, storage, item_storage)
35
44
  rescue Exception => e
36
45
  error "Copy item_storage error: #{e.message}; #{e.backtrace.join(', ')}", :item_id => item_storage.item_id, :item_storage_id => item_storage.id
46
+ $curr_tasks.delete(task)
37
47
  end
38
48
  end
@@ -34,7 +34,7 @@ module FC
34
34
 
35
35
  # get element by id
36
36
  def self.find(id)
37
- r = FC::DB.connect.query("SELECT * FROM #{self.table_name} WHERE id=#{id.to_i}")
37
+ r = FC::DB.query("SELECT * FROM #{self.table_name} WHERE id=#{id.to_i}")
38
38
  raise "Record not found (#{self.table_name}.id=#{id})" if r.count == 0
39
39
  self.create_from_fiels(r.first)
40
40
  end
@@ -43,7 +43,7 @@ module FC
43
43
  def self.where(cond = "1", *params)
44
44
  i = -1
45
45
  sql = "SELECT * FROM #{self.table_name} WHERE #{cond.gsub('?'){i+=1; "'#{Mysql2::Client.escape(params[i].to_s)}'"}}"
46
- r = FC::DB.connect.query(sql)
46
+ r = FC::DB.query(sql)
47
47
  r.map{|data| self.create_from_fiels(data)}
48
48
  end
49
49
 
@@ -63,7 +63,7 @@ module FC
63
63
  if fields.length > 0
64
64
  sql << fields.join(',')
65
65
  sql << " WHERE id=#{@id.to_i}" if @id
66
- FC::DB.connect.query(sql)
66
+ FC::DB.query(sql)
67
67
  @id = FC::DB.connect.last_id unless @id
68
68
  self.class.table_fields.each do |key|
69
69
  @database_fields[key] = self.send(key)
@@ -81,7 +81,7 @@ module FC
81
81
 
82
82
  # delete object from DB
83
83
  def delete
84
- FC::DB.connect.query("DELETE FROM #{self.class.table_name} WHERE id=#{@id.to_i}") if @id
84
+ FC::DB.query("DELETE FROM #{self.class.table_name} WHERE id=#{@id.to_i}") if @id
85
85
  end
86
86
 
87
87
  end
@@ -35,6 +35,19 @@ module FC
35
35
  end
36
36
  end
37
37
 
38
+ # connect.query with deadlock solution
39
+ def self.query(sql)
40
+ FC::DB.connect.query(sql)
41
+ rescue Mysql2::Error => e
42
+ if e.message.match('Deadlock found when trying to get lock')
43
+ puts "Deadlock"
44
+ sleep 0.1
45
+ self.query(sql)
46
+ else
47
+ raise e
48
+ end
49
+ end
50
+
38
51
  def DB.init_db
39
52
  FC::DB.connect.query(%{
40
53
  CREATE TABLE #{@prefix}items (
@@ -34,7 +34,7 @@ module FC
34
34
  if item
35
35
  if options[:replace] || storage
36
36
  # mark delete item_storages on replace
37
- FC::DB.connect.query("UPDATE #{FC::ItemStorage.table_name} SET status='delete' WHERE item_id = #{item.id}") if options[:replace] && !storage
37
+ FC::DB.query("UPDATE #{FC::ItemStorage.table_name} SET status='delete' WHERE item_id = #{item.id}") if options[:replace] && !storage
38
38
  # replace all fields
39
39
  item_params.each{|key, val| item.send("#{key}=", val)}
40
40
  else
@@ -101,7 +101,7 @@ module FC
101
101
 
102
102
  # mark items_storages for delete
103
103
  def mark_deleted
104
- FC::DB.connect.query("UPDATE #{FC::ItemStorage.table_name} SET status='delete' WHERE item_id = #{id}")
104
+ FC::DB.query("UPDATE #{FC::ItemStorage.table_name} SET status='delete' WHERE item_id = #{id}")
105
105
  self.status = 'delete'
106
106
  save
107
107
  end
@@ -115,7 +115,7 @@ module FC
115
115
  end
116
116
 
117
117
  def get_available_storages
118
- r = FC::DB.connect.query("SELECT st.* FROM #{FC::Storage.table_name} as st, #{FC::ItemStorage.table_name} as ist WHERE
118
+ r = FC::DB.query("SELECT st.* FROM #{FC::Storage.table_name} as st, #{FC::ItemStorage.table_name} as ist WHERE
119
119
  ist.item_id = #{id} AND ist.status='ready' AND ist.storage_name = st.name")
120
120
  r.map{|data| FC::Storage.create_from_fiels(data)}.select {|storage| storage.up? }
121
121
  end
@@ -1,3 +1,3 @@
1
1
  module FC
2
- VERSION = "0.1.6"
2
+ VERSION = "0.1.7"
3
3
  end
@@ -11,7 +11,7 @@ end
11
11
 
12
12
  def policies_show
13
13
  if policy = find_policy
14
- count = FC::DB.connect.query("SELECT count(*) as cnt FROM #{FC::Item.table_name} WHERE policy_id = #{policy.id}").first['cnt']
14
+ count = FC::DB.query("SELECT count(*) as cnt FROM #{FC::Item.table_name} WHERE policy_id = #{policy.id}").first['cnt']
15
15
  puts %Q{Policy
16
16
  ID: #{policy.id}
17
17
  Name: #{policy.name}
@@ -3,7 +3,7 @@ def show_current_host
3
3
  end
4
4
 
5
5
  def show_global_daemon
6
- r = FC::DB.connect.query("SELECT #{FC::DB.prefix}vars.*, UNIX_TIMESTAMP() as curr_time FROM #{FC::DB.prefix}vars WHERE name='global_daemon_host'").first
6
+ r = FC::DB.query("SELECT #{FC::DB.prefix}vars.*, UNIX_TIMESTAMP() as curr_time FROM #{FC::DB.prefix}vars WHERE name='global_daemon_host'").first
7
7
  if r
8
8
  puts "Global daemon run on #{r['val']}\nLast run #{r['curr_time']-r['time']} seconds ago."
9
9
  else
@@ -31,7 +31,7 @@ def show_host_info
31
31
  else
32
32
  puts "Info for host #{host}"
33
33
  storages.each do |storage|
34
- counts = FC::DB.connect.query("SELECT status, count(*) as cnt FROM #{FC::ItemStorage.table_name} WHERE storage_name='#{Mysql2::Client.escape(storage.name)}' GROUP BY status")
34
+ counts = FC::DB.query("SELECT status, count(*) as cnt FROM #{FC::ItemStorage.table_name} WHERE storage_name='#{Mysql2::Client.escape(storage.name)}' GROUP BY status")
35
35
  str = "#{storage.name} #{size_to_human(storage.size)}/#{size_to_human(storage.size_limit)} "
36
36
  str += "#{storage.up? ? colorize_string('UP', :green) : colorize_string('DOWN', :red)}"
37
37
  str += " #{storage.check_time_delay} seconds ago" if storage.check_time
@@ -46,17 +46,17 @@ end
46
46
 
47
47
  def show_items_info
48
48
  puts "Items by status:"
49
- counts = FC::DB.connect.query("SELECT status, count(*) as cnt FROM #{FC::Item.table_name} WHERE 1 GROUP BY status")
49
+ counts = FC::DB.query("SELECT status, count(*) as cnt FROM #{FC::Item.table_name} WHERE 1 GROUP BY status")
50
50
  counts.each do |r|
51
51
  puts " #{r['status']}: #{r['cnt']}"
52
52
  end
53
53
  puts "Items storages by status:"
54
- counts = FC::DB.connect.query("SELECT status, count(*) as cnt FROM #{FC::ItemStorage.table_name} WHERE 1 GROUP BY status")
54
+ counts = FC::DB.query("SELECT status, count(*) as cnt FROM #{FC::ItemStorage.table_name} WHERE 1 GROUP BY status")
55
55
  counts.each do |r|
56
56
  puts " #{r['status']}: #{r['cnt']}"
57
57
  end
58
- count = FC::DB.connect.query("SELECT count(*) as cnt FROM #{FC::Item.table_name} as i, #{FC::Policy.table_name} as p WHERE i.policy_id = p.id AND i.copies > 0 AND i.copies < p.copies AND i.status = 'ready'").first['cnt']
58
+ count = FC::DB.query("SELECT count(*) as cnt FROM #{FC::Item.table_name} as i, #{FC::Policy.table_name} as p WHERE i.policy_id = p.id AND i.copies > 0 AND i.copies < p.copies AND i.status = 'ready'").first['cnt']
59
59
  puts "Items to copy: #{count}"
60
- count = FC::DB.connect.query("SELECT count(*) as cnt FROM #{FC::Item.table_name} as i, #{FC::Policy.table_name} as p WHERE i.policy_id = p.id AND i.copies > p.copies AND i.status = 'ready'").first['cnt']
60
+ count = FC::DB.query("SELECT count(*) as cnt FROM #{FC::Item.table_name} as i, #{FC::Policy.table_name} as p WHERE i.policy_id = p.id AND i.copies > p.copies AND i.status = 'ready'").first['cnt']
61
61
  puts "Items to delete: #{count}"
62
62
  end
@@ -14,7 +14,7 @@ end
14
14
 
15
15
  def storages_show
16
16
  if storage = find_storage
17
- count = FC::DB.connect.query("SELECT count(*) as cnt FROM #{FC::ItemStorage.table_name} WHERE storage_name='#{Mysql2::Client.escape(storage.name)}'").first['cnt']
17
+ count = FC::DB.query("SELECT count(*) as cnt FROM #{FC::ItemStorage.table_name} WHERE storage_name='#{Mysql2::Client.escape(storage.name)}'").first['cnt']
18
18
  puts %Q{Storage
19
19
  Name: #{storage.name}
20
20
  Host: #{storage.host}
@@ -3,7 +3,7 @@ require 'helper'
3
3
  class BaseTest < Test::Unit::TestCase
4
4
  class << self
5
5
  def shutdown
6
- FC::DB.connect.query("DELETE FROM items")
6
+ FC::DB.query("DELETE FROM items")
7
7
  end
8
8
  end
9
9
 
@@ -59,10 +59,10 @@ class DaemonTest < Test::Unit::TestCase
59
59
 
60
60
  def shutdown
61
61
  Process.kill("KILL", @@pid)
62
- FC::DB.connect.query("DELETE FROM items_storages")
63
- FC::DB.connect.query("DELETE FROM items")
64
- FC::DB.connect.query("DELETE FROM policies")
65
- FC::DB.connect.query("DELETE FROM storages")
62
+ FC::DB.query("DELETE FROM items_storages")
63
+ FC::DB.query("DELETE FROM items")
64
+ FC::DB.query("DELETE FROM policies")
65
+ FC::DB.query("DELETE FROM storages")
66
66
  `rm -rf /tmp/host*-sd*`
67
67
  `rm -rf #{@@test_file_path}`
68
68
  `rm -rf #{@@test_dir_path}`
@@ -34,10 +34,10 @@ class DbTest < Test::Unit::TestCase
34
34
  @@item_storages_ids = item_storages.map{|is| is.save; is.id }
35
35
  end
36
36
  def shutdown
37
- FC::DB.connect.query("DELETE FROM items_storages")
38
- FC::DB.connect.query("DELETE FROM items")
39
- FC::DB.connect.query("DELETE FROM policies")
40
- FC::DB.connect.query("DELETE FROM storages")
37
+ FC::DB.query("DELETE FROM items_storages")
38
+ FC::DB.query("DELETE FROM items")
39
+ FC::DB.query("DELETE FROM policies")
40
+ FC::DB.query("DELETE FROM storages")
41
41
  end
42
42
  end
43
43
  def setup
@@ -33,10 +33,10 @@ class FunctionalTest < Test::Unit::TestCase
33
33
  @@policies.each { |policy| policy.save}
34
34
  end
35
35
  def shutdown
36
- FC::DB.connect.query("DELETE FROM items_storages")
37
- FC::DB.connect.query("DELETE FROM items")
38
- FC::DB.connect.query("DELETE FROM policies")
39
- FC::DB.connect.query("DELETE FROM storages")
36
+ FC::DB.query("DELETE FROM items_storages")
37
+ FC::DB.query("DELETE FROM items")
38
+ FC::DB.query("DELETE FROM policies")
39
+ FC::DB.query("DELETE FROM storages")
40
40
  `rm -rf /tmp/host*-sd*`
41
41
  `rm -rf #{@@test_file_path}`
42
42
  `rm -rf #{@@test_dir_path}`
@@ -10,8 +10,8 @@ TEST_USER = 'root'
10
10
  TEST_PASSWORD = ''
11
11
 
12
12
  FC::DB.connect_by_config(:username => TEST_USER, :password => TEST_PASSWORD)
13
- FC::DB.connect.query("DROP DATABASE IF EXISTS #{TEST_DATABASE}")
14
- FC::DB.connect.query("CREATE DATABASE #{TEST_DATABASE}")
15
- FC::DB.connect.query("USE #{TEST_DATABASE}")
13
+ FC::DB.query("DROP DATABASE IF EXISTS #{TEST_DATABASE}")
14
+ FC::DB.query("CREATE DATABASE #{TEST_DATABASE}")
15
+ FC::DB.query("USE #{TEST_DATABASE}")
16
16
  FC::DB.init_db
17
17
  FC::DB.options[:database] = TEST_DATABASE
@@ -17,9 +17,9 @@ class ItemTest < Test::Unit::TestCase
17
17
  end
18
18
  end
19
19
  def shutdown
20
- FC::DB.connect.query("DELETE FROM items_storages")
21
- FC::DB.connect.query("DELETE FROM items")
22
- FC::DB.connect.query("DELETE FROM storages")
20
+ FC::DB.query("DELETE FROM items_storages")
21
+ FC::DB.query("DELETE FROM items")
22
+ FC::DB.query("DELETE FROM storages")
23
23
  end
24
24
  end
25
25
 
@@ -14,8 +14,8 @@ class PolicyTest < Test::Unit::TestCase
14
14
  @@policy.save
15
15
  end
16
16
  def shutdown
17
- FC::DB.connect.query("DELETE FROM policies")
18
- FC::DB.connect.query("DELETE FROM storages")
17
+ FC::DB.query("DELETE FROM policies")
18
+ FC::DB.query("DELETE FROM storages")
19
19
  end
20
20
  end
21
21
 
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.1.6
4
+ version: 0.1.7
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-05-14 00:00:00.000000000 Z
12
+ date: 2013-05-22 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rb-readline
@@ -186,7 +186,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
186
186
  version: '0'
187
187
  segments:
188
188
  - 0
189
- hash: 789694035
189
+ hash: -778580397
190
190
  required_rubygems_version: !ruby/object:Gem::Requirement
191
191
  none: false
192
192
  requirements:
@@ -195,7 +195,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
195
195
  version: '0'
196
196
  segments:
197
197
  - 0
198
- hash: 789694035
198
+ hash: -778580397
199
199
  requirements: []
200
200
  rubyforge_project:
201
201
  rubygems_version: 1.8.24