lib/prometheus/client/mmaped_dict.rb in prometheus-client-mmap-0.7.0.beta12 vs lib/prometheus/client/mmaped_dict.rb in prometheus-client-mmap-0.7.0.beta13

- old
+ new

@@ -1,11 +1,12 @@ require 'prometheus/client' require 'mmap' module Prometheus module Client - class ParsingError < StandardError; end + class ParsingError < StandardError + end # A dict of doubles, backed by an mmapped file. # # The file starts with a 4 byte int, indicating how much of it is used. # Then 4 bytes of padding. @@ -21,34 +22,49 @@ def initialize(filename) @mutex = Mutex.new @f = File.open(filename, 'a+b') process_file rescue StandardError => e - raise ParsingError.new("exception #{e} while processing metrics file #{@f.path}") + raise ParsingError, "exception #{e} while processing metrics file #{@f.path}" end - # Yield (key, value, pos). No locking is performed. - def all_values - read_all_values.map { |k, v, p| [k, v] } + # Yield (key, value). No locking is performed. + def self.read_all_values(f) + m = Mmap.new(f, 'rw', Mmap::MAP_SHARED) + used, = m[0..3].unpack('l') + pos = 8 + values = [] + while pos < used + data = m.slice(pos..-1) + encoded_len, = data.unpack('l') + value_offset = 4 + encoded_len + (8 - (encoded_len + 4) % 8) + + encoded, value = data.unpack(format('@4A%d@%dd', encoded_len, value_offset)) + values << [encoded, value] + pos += value_offset + 8 + end + values + ensure + m.munmap end def read_value(key) @mutex.synchronize do - init_value(key) unless @positions.has_key?(key) + init_value(key) unless @positions.key?(key) end pos = @positions[key] # We assume that reading from an 8 byte aligned value is atomic. - @m[pos..pos+7].unpack('d')[0] + @m[pos..pos + 7].unpack('d')[0] end def write_value(key, value) @mutex.synchronize do - init_value(key) unless @positions.has_key?(key) + init_value(key) unless @positions.key?(key) end pos = @positions[key] # We assume that writing to an 8 byte aligned value is atomic. - @m[pos..pos+7] = [value].pack('d') + @m[pos..pos + 7] = [value].pack('d') end def close @m.munmap rescue TypeError => e @@ -62,13 +78,11 @@ end private def process_file - if @f.size < MINIMUM_SIZE - @f.truncate(initial_mmap_file_size) - end + @f.truncate(initial_mmap_file_size) if @f.size < MINIMUM_SIZE @capacity = @f.size @m = Mmap.new(@f.path, 'rw', Mmap::MAP_SHARED) # @m.mlock # TODO: Why does this raise an error? @@ -76,11 +90,11 @@ @used = @m[0..3].unpack('l')[0] if @used == 0 @used = 8 @m[0..3] = [@used].pack('l') else - read_all_values.each do |key, _, pos| + read_all_positions.each do |key, _, pos| @positions[key] = pos end end end @@ -102,23 +116,22 @@ @m[0..3] = [@used].pack('l') @positions[key] = @used - 8 end # Yield (key, value, pos). No locking is performed. - def read_all_values + def read_all_positions pos = 8 values = [] while pos < @used - encoded_len = @m[pos..-1].unpack('l')[0] - pos += 4 - encoded = @m[pos..-1].unpack("A#{encoded_len}")[0] - padded_len = encoded_len + (8 - (encoded_len + 4) % 8) - pos += padded_len - value = @m[pos..-1].unpack('d')[0] - values << [encoded, value, pos] + data = @m.slice(pos..-1) + encoded_len = data.unpack('l')[0] + padding_len = 8 - (encoded_len + 4) % 8 + encoded = data.unpack(format('@4A%d', encoded_len)) + pos += 4 + encoded_len + padding_len + values << [encoded, pos] pos += 8 end values end end end -end \ No newline at end of file +end