Class: FC::Item

Inherits:
DbBase show all
Defined in:
lib/fc/item.rb

Instance Attribute Summary

Attributes inherited from DbBase

#additional_fields, #database_fields, #id

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from DbBase

create_from_fiels, #delete, find, #initialize, #reload, #save, set_table, where

Constructor Details

This class inherits a constructor from FC::DbBase

Class Method Details

.create_from_local(local_path, item_name, policy, options = {}, &block) ⇒ Object

Create item by local path. Additional options:

:replace=true - replace item if it exists
:remove_local=true - delete local_path file/dir after add
:additional_fields - hash of additional FC:Item fields 
:no_md5 - don't use md5
:speed_limit - limit copy speed

If item_name is part of local_path it processed as inplace - local_path is valid path to the item for policy



17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
# File 'lib/fc/item.rb', line 17

def self.create_from_local(local_path, item_name, policy, options={}, &block)
  raise 'Path not exists' unless File.exists?(local_path)
  raise 'Policy is not FC::Policy' unless policy.instance_of?(FC::Policy)
  item_params = options.merge({
    :name => item_name.to_s.gsub('//', '/').sub(/\/$/, '').sub(/^\//, '').strip,
    :policy_id => policy.id,
    :dir => File.directory?(local_path),
    :size => FC::Storage.new(:host => FC::Storage.curr_host).file_size(local_path),
    :md5 => nil
  })
  item_params[:md5] = FC::Storage.new(
    :host => FC::Storage.curr_host
  ).md5_sum(local_path) unless item_params[:no_md5]
  item_params.delete(:replace)
  item_params.delete(:remove_local)
  item_params.delete(:not_local)
  item_params.delete(:no_md5)
  item_params.delete(:speed_limit)
  raise 'Name is empty' if item_params[:name].empty?
  raise 'Zero size path' if item_params[:size] == 0

  if local_path.include?(item_name) && !options[:not_local]
    storage = policy.get_create_storages.detect do |s|
      s.host == FC::Storage.curr_host && local_path.index(s.path) == 0 && local_path.sub(s.path, '').sub(/\/$/, '').sub(/^\//, '') == item_params[:name]
    end
    FC::Error.raise "local_path #{local_path} is not valid path for policy ##{policy.id}" unless storage
  end

  # new item?
  item = FC::Item.where('name=? AND policy_id=?', item_params[:name], policy.id).first
  if item
    if options[:replace] || storage
      # replace all fields
      item_params.each{|key, val| item.send("#{key}=", val)}
    else
      FC::Error.raise 'Item already exists', :item_id => item.id
    end
  else
    item = FC::Item.new(item_params)
  end
  item.save
  
  if storage
    item_storage = item.make_item_storage(storage, 'ready')
    item.reload
  else
    if item.copies.to_i > 0
      # find storage in item.item_storages 
      storages_names = item.get_item_storages.select{|s| s.status == 'ready'}.map(&:storage_name)
      storage = FC::Storage.select_proper_storage_for_create(policy.get_create_storages, item.size) do |storages|
        storages.select{|s| storages_names.detect(s.name)}
      end
    end
    if block_given?
      storage ||= FC::Storage.select_proper_storage_for_create(policy.get_create_storages, 
                                                               item.size, &block)
    else 
      storage ||= policy.get_proper_storage_for_create(item.size, local_path)
    end
    FC::Error.raise 'No available storage', :item_id => item.id unless storage
    
    # mark delete item_storages on replace
    FC::DB.query("UPDATE #{FC::ItemStorage.table_name} SET status='delete' WHERE item_id = #{item.id} AND storage_name <> '#{storage.name}'") if options[:replace]          
    
    item_storage = item.make_item_storage(storage)
    item.copy_item_storage(local_path, storage, item_storage, options[:remove_local], options[:speed_limit])
  end
  
  return item
end

Instance Method Details

#copy_item_storage(src, storage, item_storage, remove_local = false, speed_limit = nil) ⇒ Object



102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
# File 'lib/fc/item.rb', line 102

def copy_item_storage(src, storage, item_storage, remove_local = false, speed_limit = nil)
  begin
    if src.instance_of?(FC::Storage)
      src.copy_to_local(name, "#{storage.path}#{name}", speed_limit)
    else
      storage.copy_path(src, name, remove_local, speed_limit)
    end
    md5_on_storage = storage.md5_sum(name) if md5
  rescue Exception => e
    item_storage_status_set(item_storage, 'error')
    FC::Error.raise "Copy error: #{e.message}", :item_id => id, :item_storage_id => item_storage.id
  else
    begin
      item_storage.reload
    rescue Exception => e
      FC::Error.raise "After copy error: #{e.message}", :item_id => id, :item_storage_id => item_storage.id
    else
      if md5 && md5_on_storage != md5
        item_storage_status_set(item_storage, 'error')
        FC::Error.raise "Check md5 after copy error", :item_id => id, :item_storage_id => item_storage.id
      else
        item_storage_status_set(item_storage, 'ready')
        if remove_local && !src.instance_of?(FC::Storage) && File.exists?(src)
          if File.directory?(src)
            FileUtils.rm_r(src)
          else
            File.delete(src)
          end
        end
      end
    end
  end
end

#dir?Boolean

Returns:

  • (Boolean)


159
160
161
# File 'lib/fc/item.rb', line 159

def dir?
  dir.to_i == 1
end

#get_available_storagesObject



167
168
169
170
171
# File 'lib/fc/item.rb', line 167

def get_available_storages
  r = FC::DB.query("SELECT st.* FROM #{FC::Storage.table_name} as st, #{FC::ItemStorage.table_name} as ist WHERE 
    ist.item_id = #{id} AND ist.status='ready' AND ist.storage_name = st.name")
  r.map{|data| FC::Storage.create_from_fiels(data)}.select {|storage| storage.up? && storage.url_weight.to_i >= 0}
end

#get_item_storagesObject



163
164
165
# File 'lib/fc/item.rb', line 163

def get_item_storages
  FC::ItemStorage.where("item_id = #{id}")
end

#immediate_deleteObject

mark item and his items_storages for immediate delete



153
154
155
156
157
# File 'lib/fc/item.rb', line 153

def immediate_delete
  FC::DB.query("UPDATE #{FC::ItemStorage.table_name} SET status='delete' WHERE item_id = #{id}")
  self.status = 'delete'
  save
end

#item_storage_status_set(item_storage, status) ⇒ Object



136
137
138
139
140
141
142
143
# File 'lib/fc/item.rb', line 136

def item_storage_status_set(item_storage, status)
  reload
  marked_for_delete = self.status == 'deferred_delete'
  item_storage.status = status
  item_storage.save
  reload
  mark_deleted if marked_for_delete
end

#make_item_storage(storage, status = 'new') ⇒ Object



88
89
90
91
92
93
94
95
96
97
98
99
100
# File 'lib/fc/item.rb', line 88

def make_item_storage(storage, status = 'new')
  # new storage_item?
  item_storage = FC::ItemStorage.where('item_id=? AND storage_name=?', id, storage.name).first
  if item_storage
    item_storage.delete 
    storage.size = storage.size.to_i - size.to_i
  end
  
  item_storage = FC::ItemStorage.new({:item_id => id, :storage_name => storage.name, :status => status})
  item_storage.save
  storage.size = storage.size.to_i + size.to_i
  item_storage
end

#mark_deletedObject

mark item and his items_storages for deferred delete real delete after policy.delete_deferred_time



147
148
149
150
# File 'lib/fc/item.rb', line 147

def mark_deleted
  self.status = 'deferred_delete'
  save
end

#urlObject



177
178
179
180
181
182
183
184
185
186
187
188
# File 'lib/fc/item.rb', line 177

def url
  available_storages = get_available_storages()
  # sort by random(url_weight) 
  best_storage = available_storages.map{ |storage| 
    [storage, Kernel.rand(storage.url_weight.to_i * 100)] 
  }.sort{ |a, b|
    a[1] <=> b[1]
  }.map{|el| el[0]}.last
  best_storage = available_storages.sample unless best_storage
  raise "URL find - no avable storage for item #{id}" unless best_storage
  File.join(best_storage.url, name)
end

#urlsObject



173
174
175
# File 'lib/fc/item.rb', line 173

def urls
  get_available_storages.map{|storage| File.join(storage.url, name)}
end