Module: BitFlipper

Defined in:
lib/corruption_monkey.rb,
lib/corruption_monkey/version.rb

Defined Under Namespace

Modules: CLI

Constant Summary collapse

BitOutOfBounds =
Class.new(Exception)
VERSION =
'0.1.2'

Class Method Summary collapse

Class Method Details

.flip!(target, bit:, logger: Logger.new(nil)) ⇒ Object



7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
# File 'lib/corruption_monkey.rb', line 7

def self.flip!(target, bit:, logger: Logger.new(nil))
  logger.debug "going to flip bit with index=#{bit}"

  flip_byte, flip_bit = bit.divmod(8)

  logger.debug "computed [byte, bit]=#{[flip_byte, flip_bit]}"

  file = File.open(target, 'r+')

  file.seek(flip_byte, 0)
  byte = file.read(1)

  if byte.nil? || out_of_range(target, bit)
    raise BitOutOfBounds, "#{bit} is bigger than the offset=#{size_in_bits(target)}"
  end

  new_byte = [byte.unpack('c').first ^ (1 << flip_bit)].pack('c')

  logger.debug "readed byte: `#{byte}`: #{byte.unpack('b*').first}"
  logger.debug "writing byte: `#{new_byte}` #{new_byte.unpack('b*').first}"

  file.seek(-1, IO::SEEK_CUR)
  file.write(new_byte)

  file.fsync
  file.close
end

.flip_in_range(target, percentile:, logger: Logger.new(nil)) ⇒ Object



40
41
42
43
44
45
46
47
48
49
# File 'lib/corruption_monkey.rb', line 40

def self.flip_in_range(target, percentile:, logger: Logger.new(nil))
  # TODO(javierhonduco): Improve error checking (╯ರ ~ ರ)
  bit_to_flip = (size_in_bits(target) * percentile/101.0).to_i

  if out_of_range(target, bit_to_flip)
    raise IndexError, "percentile=#{percentile} not in range"
  end

  flip!(target, bit: bit_to_flip, logger: logger)
end

.out_of_range(file, bit) ⇒ Object



55
56
57
# File 'lib/corruption_monkey.rb', line 55

def self.out_of_range(file, bit)
  bit < 0 || bit > size_in_bits(file)
end

.random_bit_flip(target, logger: Logger.new(nil)) ⇒ Object



35
36
37
38
# File 'lib/corruption_monkey.rb', line 35

def self.random_bit_flip(target, logger: Logger.new(nil))
  computed_bit = rand(0...size_in_bits(target))
  flip!(target, bit: computed_bit, logger: logger)
end

.size_in_bits(file) ⇒ Object



51
52
53
# File 'lib/corruption_monkey.rb', line 51

def self.size_in_bits(file)
  File.size(file) * 8
end