Skip to content
This repository was archived by the owner on Mar 17, 2023. It is now read-only.

Commit c60e3af

Browse files
committed
Fix inconsistent chunking
The chunking performed within RestorePlan#price and Cli#restore was inconsistent. This did not show because of the memoization that existed previously.
1 parent 0f13782 commit c60e3af

File tree

3 files changed

+23
-24
lines changed

3 files changed

+23
-24
lines changed

lib/tina/cli.rb

+3-3
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,9 @@ def restore(prefix_file)
1616

1717
prefixes = File.readlines(prefix_file).map(&:chomp)
1818
objects = RestorePlan::ObjectCollection.new(s3_client.list_bucket_prefixes(prefixes))
19-
restore_plan = RestorePlan.new(total_storage.to_i, objects)
20-
price = restore_plan.price(duration_in_seconds)
21-
chunks = objects.chunk(duration_in_seconds)
19+
restore_plan = RestorePlan.new(total_storage.to_i, objects, duration_in_seconds)
20+
price = restore_plan.price
21+
chunks = restore_plan.object_chunks
2222
say
2323
say "Restores will be performed in the following chunks:"
2424
say "-" * 60

lib/tina/restore_plan.rb

+12-9
Original file line numberDiff line numberDiff line change
@@ -5,31 +5,34 @@ class RestorePlan
55
DAYS_PER_MONTH = 30
66
PRICE_PER_GB_PER_HOUR = 0.011
77

8-
def initialize(total_storage_size, objects, options = {})
8+
def initialize(total_storage_size, objects, total_time, options = {})
99
@total_storage_size = total_storage_size
1010
@objects = objects
11+
@total_time = [total_time, 4 * 3600].max
1112
@price_per_gb_per_hour = options[:price_per_gb_per_hour] || PRICE_PER_GB_PER_HOUR
1213

1314
@daily_allowance = @total_storage_size * MONTHLY_FREE_TIER_ALLOWANCE_FACTOR / DAYS_PER_MONTH
1415
end
1516

16-
def price(total_time)
17-
total_time = [total_time, 4 * 3600].max
18-
chunk_size = quadhourly_restore_rate(total_time)
19-
chunks = @objects.chunk(chunk_size)
20-
largest_chunk_object_size = chunks.map { |chunk| chunk.map(&:size).reduce(&:+) }.max
21-
quadhours = chunks.size
17+
def price
18+
largest_chunk_object_size = object_chunks.map { |chunk| chunk.map(&:size).reduce(&:+) }.max
19+
quadhours = object_chunks.size
2220
quadhourly_allowance = @daily_allowance / ( [(24 / 4), quadhours].min * 4)
2321

2422
peak_retrieval_rate = largest_chunk_object_size / 4
2523
peak_billable_retrieval_rate = [0, peak_retrieval_rate - quadhourly_allowance].max
2624

2725
peak_billable_retrieval_rate * (@price_per_gb_per_hour / 1024 ** 3) * 720
2826
end
27+
28+
def object_chunks
29+
@object_chunks ||= @objects.chunk(quadhourly_restore_rate)
30+
end
31+
2932
private
3033

31-
def quadhourly_restore_rate(total_time)
32-
@objects.total_size / (total_time / (4 * 3600))
34+
def quadhourly_restore_rate
35+
@objects.total_size / (@total_time / (4 * 3600))
3336
end
3437

3538
class ObjectCollection

spec/tina/restore_plan_spec.rb

+8-12
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,6 @@
22

33
module Tina
44
describe RestorePlan do
5-
subject do
6-
described_class.new(total_storage_size, object_collection, options)
7-
end
8-
95
let :total_storage_size do
106
75 * (1024 ** 4)
117
end
@@ -29,15 +25,15 @@ module Tina
2925
# http://aws.amazon.com/glacier/faqs/
3026
context 'with the examples given on the Amazon Glacier pricing FAQ' do
3127
it 'matches the the price for a restore with everything at once' do
32-
expect(subject.price(4 * 3600)).to be_within(0.05).of(21.6)
28+
expect(described_class.new(total_storage_size, object_collection, 4 * 3600, options).price).to be_within(0.05).of(21.6)
3329
end
3430

3531
it 'matches the the price for a restore over 8 hours' do
36-
expect(subject.price(8 * 3600)).to be_within(0.05).of(10.8)
32+
expect(described_class.new(total_storage_size, object_collection, 8 * 3600, options).price).to be_within(0.05).of(10.8)
3733
end
3834

3935
it 'matches the the price for a restore over 28 hours' do
40-
expect(subject.price(28 * 3600)).to eq 0
36+
expect(described_class.new(total_storage_size, object_collection, 28 * 3600, options).price).to eq 0
4137
end
4238
end
4339

@@ -58,19 +54,19 @@ module Tina
5854
end
5955

6056
it 'matches the price for a restore over a month' do
61-
expect(subject.price(30 * 24 * 3600)).to be_within(0.05).of(4.16)
57+
expect(described_class.new(total_storage_size, object_collection, 30 * 24 * 3600, options).price).to be_within(0.05).of(4.16)
6258
end
6359

6460
it 'matches the price for a restore over a week' do
65-
expect(subject.price(7 * 24 * 3600)).to be_within(0.05).of(437.87)
61+
expect(described_class.new(total_storage_size, object_collection, 7 * 24 * 3600, options).price).to be_within(0.05).of(437.87)
6662
end
6763

6864
it 'matches the price for a restore over a day' do
69-
expect(subject.price(1 * 24 * 3600)).to be_within(0.05).of(3832.16)
65+
expect(described_class.new(total_storage_size, object_collection, 1 * 24 * 3600, options).price).to be_within(0.05).of(3832.16)
7066
end
7167

7268
it 'matches the price for a restore over a 4 hour period' do
73-
expect(subject.price(4 * 3600)).to be_within(0.05).of(22992.93)
69+
expect(described_class.new(total_storage_size, object_collection, 4 * 3600, options).price).to be_within(0.05).of(22992.93)
7470
end
7571
end
7672

@@ -84,7 +80,7 @@ module Tina
8480
end
8581

8682
it 'matches the price for a restore over 4 days' do
87-
expect(subject.price(4 * 24 * 3600)).to be_within(20).of(768)
83+
expect(described_class.new(total_storage_size, object_collection, 4 * 24 * 3600, options).price).to be_within(20).of(768)
8884
end
8985
end
9086
end

0 commit comments

Comments
 (0)