class Fireworks::BlockDevice

Attributes

device[R]
interval[R]
threads[R]

Public Class Methods

new(device:, threads: 1, interval: 5) click to toggle source
# File lib/fireworks/block_device.rb, line 9
def initialize(device:, threads: 1, interval: 5)
  @threadpool = []

  @device = device
  @threads = threads
  @interval = interval
  raise ArgumentError, "Device #{device} does not exist" unless File.exist?(device)
  raise ArgumentError, "Device #{device} is empty" unless device_size > 0
  raise ArgumentError, "Device #{device} is already mounted" if already_mounted?
end

Public Instance Methods

already_mounted?() click to toggle source
# File lib/fireworks/block_device.rb, line 24
def already_mounted?
  !`mount | grep #{device}`.empty?
end
current_stats() click to toggle source
# File lib/fireworks/block_device.rb, line 39
def current_stats
  {
    bytes_completed: @threadpool.map(&:bytes_completed).inject(:+),
    total_rate: @threadpool.map(&:rate).inject(:+),
    num_up_to_date: @threadpool.select(&:up_to_date?).size,
    num_complete: @threadpool.select(&:complete?).size
  }
end
device_size() click to toggle source
# File lib/fireworks/block_device.rb, line 20
def device_size
  @device_size ||= `blockdev --getsize64 #{device}`.to_i
end
output_stats() click to toggle source
# File lib/fireworks/block_device.rb, line 48
def output_stats
  stats = current_stats
  bytes_completed = Filesize.new(stats[:bytes_completed])
  total_rate = Filesize.new(stats[:total_rate])
  device_file_size = Filesize.new(device_size)
  time_left = ((device_file_size - bytes_completed) / total_rate)
  puts format(
    '%s / %s (%.2f%%) [%s/s] %d UpToDate - %d Complete - ETA %s',
    bytes_completed.pretty,
    device_file_size.pretty,
    100.0 * bytes_completed / device_file_size,
    total_rate.pretty,
    stats[:num_up_to_date],
    stats[:num_complete],
    total_rate > 0 ? ChronicDuration.output(time_left, format: :short) : 'Infinity'
  )
end
prewarm() click to toggle source
# File lib/fireworks/block_device.rb, line 28
def prewarm
  start_threads

  until @threadpool.all?(&:complete?)
    @threadpool.each(&:update_status)

    output_stats
    sleep interval
  end
end

Private Instance Methods

start_threads() click to toggle source
# File lib/fireworks/block_device.rb, line 68
def start_threads
  total_chunks = Filesize.new(device_size) / Filesize.from('1MiB')
  chunks_per_thread = (total_chunks / threads).to_i

  1.upto(threads).each do |thread_num|
    start_point = chunks_per_thread * (thread_num - 1)

    stdin, stdout, stderr, thread = Open3.popen3("dd if=#{device} of=#{device} bs=1M skip=#{start_point} seek=#{start_point} count=#{chunks_per_thread} conv=notrunc")
    stdin.close
    stdout.close

    @threadpool.push(Fireworks::DDThread.new(thread: thread, stderr: stderr))
  end
end