mir 0.1.3 → 0.1.4

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.
@@ -0,0 +1,6 @@
1
+ # Mir Changelog
2
+
3
+ ### 0.1.4
4
+
5
+ * Fixed bug that occurred during pull operations when the connection with Amazon S3 is interrupted mid-transmission. Pull operations will now continue to download an asset from S3 until the checksum matches what has been stored in the local index
6
+ * Added configuration option max_download_attempts to allow the user to set the maximum number of pull attempts per file
data/README.md CHANGED
@@ -16,7 +16,8 @@ The inspiration for this tool is to provide similar functionality to the classic
16
16
  Mir uses a YAML file for configuration settings. Unless you specify otherwise, Mir will look for the file 'mir_settings.yml' in the HOME and /etc/mir directories.
17
17
 
18
18
  settings:
19
- max_upload_retries: 5
19
+ max_upload_attempts: 5
20
+ max_download_attempts: 5
20
21
  max_threads: 5
21
22
  cloud_provider:
22
23
  type: s3
@@ -7,7 +7,7 @@ module Mir
7
7
  class Application
8
8
 
9
9
  DEFAULT_SETTINGS_FILE_NAME = "mir_settings.yml"
10
- DEFAULT_BATCH_SIZE = 20
10
+ DEFAULT_BATCH_SIZE = 100
11
11
 
12
12
  # Creates a new Mir instance
13
13
  def self.start
@@ -146,37 +146,53 @@ module Mir
146
146
 
147
147
  # Copy the remote disk contents into the specified directory
148
148
  def pull(target)
149
- Utils.try_create_dir(target)
150
- write_dir = Dir.new(target)
149
+ write_dir = Utils.try_create_dir(target)
151
150
  Mir.logger.info "Copying remote disk to #{write_dir.path} using #{config.max_threads} threads"
151
+ failed_downloads = []
152
152
 
153
153
  time = Benchmark.measure do
154
154
  queue = WorkQueue.new(config.max_threads)
155
-
156
- # loop through each resource. If the resource is a directory, create the path
157
- # otherwise download the file
155
+
158
156
  Models::Resource.ordered_groups(DEFAULT_BATCH_SIZE) do |resources|
159
- resources.each do |resource|
160
- dest = File.join(write_dir.path, resource.filename)
161
- if resource.is_directory?
162
- Utils.try_create_dir(dest)
163
- elsif !resource.synchronized?(dest)
164
- queue.enqueue_b do
165
- disk.copy(resource.abs_path, dest)
166
- if resource.synchronized?(dest)
167
- Mir.logger.info "Successful download #{dest}"
168
- puts "Pulled #{dest}"
169
- else
170
- Mir.logger.error "Incomplete download #{dest}"
157
+ # Track the number of download attempts made per resource
158
+ batch = resources.inject({}) { |set, resource| set[resource] = 0; set }
159
+
160
+ while !batch.empty? do
161
+ batch.each do |resource, attempts|
162
+ dest = File.join(write_dir.path, resource.filename)
163
+ if resource.is_directory?
164
+ Utils.try_create_dir(dest)
165
+ batch.delete(resource)
166
+ elsif attempts >= config.max_download_attempts
167
+ Mir.logger.info "Resource #{resource.abs_path} failed to download"
168
+ failed_downloads << resource
169
+ batch.delete(resource)
170
+ elsif resource.synchronized? dest
171
+ Mir.logger.debug "Skipping already downloaded file #{resource.abs_path}"
172
+ batch.delete(resource)
173
+ else
174
+ batch[resource] += 1
175
+ queue.enqueue_b do
176
+ Mir.logger.debug "Beginning download of #{resource.abs_path}"
177
+ disk.copy(resource.abs_path, dest)
178
+ if resource.synchronized? dest
179
+ FileUtils.chmod_R 0755, dest # allow binaries to execute
180
+ puts "Pulled #{dest}"
181
+ batch.delete(resource)
182
+ end
171
183
  end
172
184
  end
173
185
  end
186
+ queue.join
174
187
  end
175
- queue.join
176
188
  end
177
189
  end
178
190
  Mir.logger.info time
179
191
  puts "Completed pull operation #{time}"
192
+ unless failed_downloads.empty?
193
+ puts "The following files failed to download after several attempts:\n}"
194
+ puts failed_downloads.join("\n")
195
+ end
180
196
  end
181
197
 
182
198
  end
@@ -1,5 +1,3 @@
1
-
2
-
3
1
  # The config class is used for storage of user settings and preferences releated to
4
2
  # S3 storage
5
3
  module Mir
@@ -10,9 +8,20 @@ module Mir
10
8
  def initialize(config_file = nil)
11
9
  @config_file = config_file
12
10
  @settings, @database = nil, nil
11
+
12
+ self.max_upload_attempts = 10
13
+ self.max_download_attempts = 10
14
+ self.max_threads = 5
15
+
16
+ yield self if block_given?
13
17
  end
14
18
 
19
+ attr_accessor :max_upload_attempts, :max_download_attempts, :max_threads
20
+
15
21
  # Validates configuration settings
22
+ # TODO: move this into a class method responsible for parsing the YAML file. We
23
+ # shouldn't have to explicitly check for a valid object unless the user has provided
24
+ # a settings file
16
25
  def valid?
17
26
  if @config_file.nil? or !File.exist?(@config_file)
18
27
  Mir.logger.error("Configuration file not found")
@@ -101,7 +101,7 @@ module Mir
101
101
 
102
102
  def update_failure
103
103
  num_times_failed = times_failed + 1
104
- will_requeue = (num_times_failed < Mir::Application.config.max_upload_retries)
104
+ will_requeue = (num_times_failed < Mir::Application.config.max_upload_attempts)
105
105
  update_attributes :times_failed => num_times_failed, :in_progress => false, :queued => will_requeue
106
106
  end
107
107
 
@@ -11,6 +11,7 @@ module Mir
11
11
 
12
12
  def self.try_create_dir(path)
13
13
  Dir.mkdir(path) unless Dir.exist?(path)
14
+ Dir.new(path)
14
15
  end
15
16
 
16
17
  # Splits a file into pieces that may be reassembled later
@@ -1,5 +1,5 @@
1
1
  module Mir
2
- VERSION = [0,1,3]
2
+ VERSION = [0,1,4]
3
3
 
4
4
  def self.version
5
5
  VERSION.join('.')
metadata CHANGED
@@ -2,7 +2,7 @@
2
2
  name: mir
3
3
  version: !ruby/object:Gem::Version
4
4
  prerelease:
5
- version: 0.1.3
5
+ version: 0.1.4
6
6
  platform: ruby
7
7
  authors:
8
8
  - Nate Miller
@@ -10,7 +10,7 @@ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
12
 
13
- date: 2011-09-22 00:00:00 -07:00
13
+ date: 2011-09-23 00:00:00 -07:00
14
14
  default_executable:
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
@@ -90,6 +90,7 @@ extra_rdoc_files: []
90
90
 
91
91
  files:
92
92
  - .gitignore
93
+ - CHANGELOG.md
93
94
  - Gemfile
94
95
  - LICENSE
95
96
  - README.md