Module: MiqDiskCache

Defined in:
lib/disk/modules/miq_disk_cache.rb

Constant Summary collapse

MIN_SECTORS_PER_ENTRY =
32
DEF_LRU_HASH_ENTRIES =
100
DEBUG_CACHE_STATS =
false

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(m, *args) ⇒ Object



105
106
107
# File 'lib/disk/modules/miq_disk_cache.rb', line 105

def method_missing(m, *args)
  @up_stream.send(m, *args)
end

Instance Attribute Details

#blockSizeObject (readonly)

Returns the value of attribute blockSize.



10
11
12
# File 'lib/disk/modules/miq_disk_cache.rb', line 10

def blockSize
  @blockSize
end

#cache_hitsObject (readonly)

Returns the value of attribute cache_hits.



10
11
12
# File 'lib/disk/modules/miq_disk_cache.rb', line 10

def cache_hits
  @cache_hits
end

#cache_missesObject (readonly)

Returns the value of attribute cache_misses.



10
11
12
# File 'lib/disk/modules/miq_disk_cache.rb', line 10

def cache_misses
  @cache_misses
end

#d_sizeObject (readonly)

Returns the value of attribute d_size.



10
11
12
# File 'lib/disk/modules/miq_disk_cache.rb', line 10

def d_size
  @d_size
end

#lru_hash_entriesObject (readonly)

Returns the value of attribute lru_hash_entries.



10
11
12
# File 'lib/disk/modules/miq_disk_cache.rb', line 10

def lru_hash_entries
  @lru_hash_entries
end

#min_sectors_per_entryObject (readonly)

Returns the value of attribute min_sectors_per_entry.



10
11
12
# File 'lib/disk/modules/miq_disk_cache.rb', line 10

def min_sectors_per_entry
  @min_sectors_per_entry
end

Class Method Details

.new(up_stream, lru_hash_entries = DEF_LRU_HASH_ENTRIES, min_sectors_per_entry = MIN_SECTORS_PER_ENTRY) ⇒ Object



12
13
14
15
16
17
18
19
20
21
# File 'lib/disk/modules/miq_disk_cache.rb', line 12

def self.new(up_stream, lru_hash_entries = DEF_LRU_HASH_ENTRIES, min_sectors_per_entry = MIN_SECTORS_PER_ENTRY)
  raise "MiqDiskCache: Downstream Disk Module is nil" if up_stream.nil?
  @dInfo                       = OpenStruct.new
  @dInfo.lru_hash_entries      = lru_hash_entries
  @dInfo.min_sectors_per_entry = min_sectors_per_entry
  @dInfo.block_size            = up_stream.blockSize
  @dInfo.up_stream             = up_stream

  MiqDisk.new(self, @dInfo, 0)
end

Instance Method Details

#d_closeObject



100
101
102
103
# File 'lib/disk/modules/miq_disk_cache.rb', line 100

def d_close
  hit_or_miss if DEBUG_CACHE_STATS
  @up_stream.d_close
end

#d_initObject



23
24
25
26
27
28
29
30
# File 'lib/disk/modules/miq_disk_cache.rb', line 23

def d_init
  @block_cache           = LruHash.new(@dInfo.lru_hash_entries)
  @cache_hits            = Hash.new(0)
  @cache_misses          = Hash.new(0)
  @blockSize             = @dInfo.block_size
  @up_stream             = @dInfo.up_stream
  @min_sectors_per_entry = @dInfo.min_sectors_per_entry
end

#d_read(pos, len) ⇒ Object



40
41
42
43
44
45
46
47
48
# File 'lib/disk/modules/miq_disk_cache.rb', line 40

def d_read(pos, len)
  $log.debug "MiqDiskCache.d_read(#{pos}, #{len})"
  return nil if pos >= @endByteAddr
  len = @endByteAddr - pos if (pos + len) > @endByteAddr
  start_sector, start_offset = pos.divmod(@blockSize)
  end_sector                 = (pos + len - 1) / @blockSize
  number_sectors             = end_sector - start_sector + 1
  d_read_cached(start_sector, number_sectors)[start_offset, len]
end

#d_read_cached(start_sector, number_sectors) ⇒ Object



50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
# File 'lib/disk/modules/miq_disk_cache.rb', line 50

def d_read_cached(start_sector, number_sectors)
  $log.debug "MiqDiskCache.d_read_cached(#{start_sector}, #{number_sectors})"
  @block_cache.keys.each do |block_range|
    sector_offset = start_sector - block_range.first
    buffer_offset = sector_offset * @blockSize
    if block_range.include?(start_sector) && block_range.include?(start_sector + number_sectors - 1)
      length = number_sectors * @blockSize
      @cache_hits[start_sector] += 1
      return @block_cache[block_range][buffer_offset, length]
    elsif block_range.include?(start_sector)
      # This range overlaps the start of our requested reqd, but more data is required at the end of the request
      sectors_in_range = block_range.last - start_sector
      length           = sectors_in_range * @blockSize
      remaining_blocks = number_sectors - sectors_in_range
      @cache_hits[start_sector] += 1
      # The "+" operator is required rather than "<<" so as not to modify the @block_cache object
      return @block_cache[block_range][buffer_offset, length] + d_read_cached(block_range.last + 1, remaining_blocks)
    elsif block_range.include?(start_sector + number_sectors - 1)
      # This range overlaps the end of our requested read, but more data is required at the start of the request
      sectors_in_range = (start_sector + number_sectors) - block_range.first
      length           = sectors_in_range * @blockSize
      remaining_blocks = number_sectors - sectors_in_range
      @cache_hits[start_sector] += 1
      # The "<<" operator is valid and more efficient here
      return d_read_cached(start_sector, remaining_blocks) << @block_cache[block_range][0, length]
    elsif block_range.first > start_sector && block_range.last < start_sector + number_sectors
      # This range overlaps our requested read but more data is required both before and after the range
      sectors_in_range   = block_range.last - block_range.first + 1
      sectors_pre_range  = block_range.first - start_sector
      sectors_post_range = number_sectors - sectors_in_range - sectors_pre_range
      # Note the mixed use of operators below.
      # The first "<<" operator is valid and more efficient while the second "+" operator
      # is required instead so as not to modify the in-place @block_cache object.
      return d_read_cached(start_sector, sectors_pre_range) <<
             @block_cache[block_range] +
             d_read_cached(block_range.last + 1, sectors_post_range)
    end
  end
  block_range               = entry_range(start_sector, number_sectors)
  range_length              = (block_range.last - block_range.first + 1) * @blockSize
  @block_cache[block_range] = @up_stream.d_read(block_range.first * @blockSize, range_length)
  @cache_misses[start_sector] += 1

  sector_offset = start_sector - block_range.first
  buffer_offset = sector_offset * @blockSize
  length        = number_sectors * @blockSize

  @block_cache[block_range][buffer_offset, length]
end

#dInfoObject



36
37
38
# File 'lib/disk/modules/miq_disk_cache.rb', line 36

def dInfo
  @up_stream.dInfo
end

#respond_to_missing(_method_name, _include_private = false) ⇒ Object



109
110
111
# File 'lib/disk/modules/miq_disk_cache.rb', line 109

def respond_to_missing(_method_name, _include_private = false)
  true
end