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

apply!, create_from_fiels, #delete, #dump, find, #initialize, #load, #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
:force_local_storage

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



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
87
88
89
90
91
92
93
94
95
# File 'lib/fc/item.rb', line 18

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)
  item_params.delete(:force_local_storage)
  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]
    if options[:force_local_storage]
      storage = options[:force_local_storage]
      if local_path.index(storage.path) != 0 || local_path.sub(storage.path, '').sub(/\/$/, '').sub(/^\//, '') != item_params[:name]
        FC::Error.raise "force_local_storage #{storage.name} is not valid path for local path ##{local_path}"
      end
    else
      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
  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



111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
# File 'lib/fc/item.rb', line 111

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)


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

def dir?
  dir.to_i == 1
end

#get_available_storagesObject



176
177
178
179
180
181
182
183
184
# File 'lib/fc/item.rb', line 176

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")
  istorages = r.map { |data| FC::Storage.create_from_fiels(data) }
               .select { |storage| storage.up? && storage.url_weight.to_i >= 0 }
  http_up_storages = istorages.select(&:http_up?)
  istorages = http_up_storages if http_up_storages.any?
  istorages
end

#get_item_storagesObject



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

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

#immediate_deleteObject

mark item and his items_storages for immediate delete



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

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



145
146
147
148
149
150
151
152
# File 'lib/fc/item.rb', line 145

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



97
98
99
100
101
102
103
104
105
106
107
108
109
# File 'lib/fc/item.rb', line 97

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



156
157
158
159
# File 'lib/fc/item.rb', line 156

def mark_deleted
  self.status = 'deferred_delete'
  save
end

#urlObject



190
191
192
193
194
195
196
197
198
199
200
# File 'lib/fc/item.rb', line 190

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_by { |a| a[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



186
187
188
# File 'lib/fc/item.rb', line 186

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