Skip to content

Commit

Permalink
Optimize the handling of binary items
Browse files Browse the repository at this point in the history
When writing large binary items (e.g. audio or video files), creating a
hard link pointing to the original avoids duplicating the data on disk.
This is specially useful for large binary items.

Hard linking will fail when the source file is not on the same device as
the output directory (e.g. when /tmp is a tmpfs). In that case, fallback
to the previous behavior of copying, what does duplicate the space, but
should always work.
  • Loading branch information
terceiro committed Feb 27, 2018
1 parent d12be32 commit 17eb486
Show file tree
Hide file tree
Showing 2 changed files with 17 additions and 2 deletions.
8 changes: 7 additions & 1 deletion nanoc/lib/nanoc/base/services/item_rep_writer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,13 @@ def write_single(item_rep, snapshot_repo, snapshot_name, raw_path, written_paths
is_modified = is_created || !FileUtils.identical?(raw_path, temp_path)

# Write
FileUtils.cp(temp_path, raw_path) if is_modified
if is_modified
begin
FileUtils.ln(temp_path, raw_path, force: true)
rescue Errno::EXDEV
FileUtils.cp(temp_path, raw_path)
end
end

item_rep.modified = is_modified

Expand Down
11 changes: 10 additions & 1 deletion nanoc/spec/nanoc/base/item_rep_writer_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@
File.write(snapshot_contents[:donkey].filename, 'binary donkey stuff')
end

it 'copies' do
it 'copies contents' do
expect(Nanoc::Int::NotificationCenter).to receive(:post)
.with(:rep_write_started, item_rep, 'output/blah.dat')
expect(Nanoc::Int::NotificationCenter).to receive(:post)
Expand All @@ -65,6 +65,15 @@
expect(File.read('output/blah.dat')).to eql('binary donkey stuff')
end

it 'uses hard links' do
subject

input = File.stat(snapshot_contents[:donkey].filename)
output = File.stat('output/blah.dat')

expect(input.ino).to eq(output.ino)
end

context 'output file already exists' do
let(:old_mtime) { Time.at((Time.now - 600).to_i) }

Expand Down

0 comments on commit 17eb486

Please sign in to comment.