Skip to content

Instantly share code, notes, and snippets.

@casperisfine
Created October 1, 2019 09:52
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save casperisfine/53171c14c135bf61979f328926d9ee34 to your computer and use it in GitHub Desktop.
Save casperisfine/53171c14c135bf61979f328926d9ee34 to your computer and use it in GitHub Desktop.
require 'zlib'
require 'benchmark'
require 'rubygems/package'
require 'rubygems/package/tar_reader'
duration = Benchmark.realtime do
tar = Gem::Package::TarReader.new(Zlib::GzipReader.open(ARGV.first))
tar.each { |_| }
end
p duration
class Gem::Package::TarReader
def each
return enum_for __method__ unless block_given?
use_seek = @io.respond_to?(:seek)
until @io.eof? do
header = Gem::Package::TarHeader.from @io
return if header.empty?
entry = Gem::Package::TarReader::Entry.new header, @io
size = entry.header.size
yield entry
skip = (512 - (size % 512)) % 512
pending = size - entry.bytes_read
if use_seek
begin
# avoid reading if the @io supports seeking
@io.seek pending, IO::SEEK_CUR
pending = 0
rescue Errno::EINVAL
end
end
# if seeking didn't work
while pending > 0 do
bytes_read = @io.read([pending, 4096].min).size
raise UnexpectedEOF if @io.eof?
pending -= bytes_read
end
@io.read skip # discard trailing zeros
# make sure nobody can use #read, #getc or #rewind anymore
entry.close
end
end
end
duration = Benchmark.realtime do
tar = Gem::Package::TarReader.new(Zlib::GzipReader.open(ARGV.first))
tar.each { |_| }
end
p duration
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment