prometheus-client-mmap 0.7.0.beta14 → 0.7.0.beta15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: ed314a3faf8c4af821870d160f43519e49dd7ebd
4
- data.tar.gz: cf39eae7140111a9216475d159597dbe86c21384
3
+ metadata.gz: 84f31b1815d567cd2d00583255372973f739fad7
4
+ data.tar.gz: b2752140fb46a42db2081099a42943d33dc890d5
5
5
  SHA512:
6
- metadata.gz: 7ccd3d06b4635af116a2538c3519bf63a5b5c939cbdbb6d29414e61635162e0d099afb926b9a1d462f2f8946b4f6800f9da88819e10ebb05e7055f3d6e53e02a
7
- data.tar.gz: 4a4ed88916f09e41acbb0ed6193e4b767e4f0d03ec4461305332b401018dd847ba503bc699c145916856284c331921e8cab3495c5367412b882f58af129028c2
6
+ metadata.gz: 8b2e8c8b8ec3ea087da3d13e142c24622b56c007aa8679dc18beb4bd1ae66a28ef72344bcfa531c39e2c5778d83e3ba563b56cdcd49dfb811b4e6b34ace2f99d
7
+ data.tar.gz: 71488cc0a7a41f9c0cc230c11305d654f813b94502d440dd37ee98e79cf43feba70959ee9985a172b8778226de8035a78dac29d45e19f6a220b8a93ad33fe866
@@ -96,6 +96,7 @@ module Prometheus
96
96
  metrics = {}
97
97
  Dir.glob(File.join(path, '*.db')).sort.each do |f|
98
98
  parts = File.basename(f, '.db').split('_')
99
+ parts[-1].gsub!(/(?<=.)-\d+/, '') # remove trailing file number
99
100
  type = parts[0].to_sym
100
101
 
101
102
  MmapedDict.read_all_values(f).each do |key, value|
@@ -0,0 +1,150 @@
1
+ require 'prometheus/client'
2
+ require 'mmap'
3
+
4
+ module Prometheus
5
+ module Client
6
+ module Helper
7
+ class MmapedFile < Mmap
8
+ MINIMUM_SIZE = 8
9
+ attr_reader :filepath, :size
10
+
11
+ def initialize(filepath, mode = 'r', protection = Mmap::MAP_SHARED, options = {})
12
+ @filepath = filepath
13
+
14
+ File.open(filepath, 'a+b') do |file|
15
+ file.truncate(initial_mmap_file_size) if file.size < MINIMUM_SIZE
16
+ @size = file.size
17
+ end
18
+
19
+ super(filepath, mode, protection, options)
20
+ end
21
+
22
+ def pid
23
+ self[0..3].unpack('l')[0]
24
+ end
25
+
26
+ def pid=(value)
27
+ self[0..3] = [value].pack('l')
28
+ end
29
+
30
+ def used
31
+ self[4..7].unpack('l')[0]
32
+ end
33
+
34
+ def used=(value)
35
+ self[4..7] = [value].pack('l')
36
+ end
37
+
38
+ def locked_to_process?
39
+ pid > 0
40
+ end
41
+
42
+ def lock_owner?
43
+ pid == Process.pid
44
+ end
45
+
46
+ def lock_to_process
47
+ return true if lock_owner?
48
+
49
+ if locked_to_process?
50
+ false
51
+ else
52
+ self.pid = Process.pid
53
+
54
+ # check if PID was correctly written
55
+ lock_owner?
56
+ end
57
+ end
58
+
59
+ def unlock
60
+ return unless lock_owner?
61
+
62
+ self.pid = 0
63
+ end
64
+
65
+ def initial_mmap_file_size
66
+ Prometheus::Client.configuration.initial_mmap_file_size
67
+ end
68
+
69
+ def entries
70
+ return Enumerator.new {} if used.zero?
71
+
72
+ Enumerator.new do |yielder|
73
+ used_ = used # cache used to avoid unnecessary unpack operations
74
+
75
+ pos = 12 # pid + used + padding offset
76
+ while pos < used_
77
+ data = slice(pos..-1)
78
+ encoded_len, = data.unpack('l')
79
+ padding_len = 8 - (encoded_len + 4) % 8
80
+ value_offset = 4 + encoded_len + padding_len
81
+
82
+ yielder.yield data, encoded_len, value_offset
83
+
84
+ pos += value_offset + 8
85
+ end
86
+ end
87
+ end
88
+
89
+ def add_entry(data, value)
90
+ self.used = 12 if used.zero?
91
+
92
+ # Pad to be 8-byte aligned.
93
+ padded = data + (' ' * (8 - (data.length + 4) % 8))
94
+ entry = [data.length, padded, value].pack("lA#{padded.length}d")
95
+ used_ = used
96
+
97
+ while (used_ + entry.length) > @size do
98
+ extend(size)
99
+ @size = File.size(filepath)
100
+ end
101
+
102
+ self[used_..used_ + entry.length] = entry
103
+
104
+ self.used = used_ + entry.length
105
+ end
106
+
107
+ def close
108
+ munmap
109
+ end
110
+
111
+ class << self
112
+ def open_readonly(filepath)
113
+ MmapedFile.new(filepath, 'r', Mmap::MAP_PRIVATE)
114
+ end
115
+
116
+ def open(filepath)
117
+ MmapedFile.new(filepath, 'rw', Mmap::MAP_SHARED)
118
+ end
119
+
120
+ def lock_to_process(filepath)
121
+ m = open(filepath)
122
+ if m.lock_to_process
123
+ Kernel.at_exit do
124
+ open(filepath).unlock
125
+ end
126
+ end
127
+ ensure
128
+ m.close
129
+ end
130
+
131
+ def ensure_process_exclusive_file(file_prefix = 'mmaped_file')
132
+ path = nil
133
+ filename_number = 0
134
+ until path && Helper::MmapedFile.lock_to_process(path)
135
+ filename = "#{file_prefix}_#{Prometheus::Client.pid}-#{filename_number}.db"
136
+ path = File.join(Prometheus::Client.configuration.multiprocess_files_dir, filename)
137
+ filename_number += 1
138
+ end
139
+ path
140
+ end
141
+
142
+ def open_process_exclusive_file(file_prefix = 'mmaped_file')
143
+ filename = Helper::MmapedFile.ensure_process_exclusive_file(file_prefix)
144
+ open(filename)
145
+ end
146
+ end
147
+ end
148
+ end
149
+ end
150
+ end
@@ -1,5 +1,5 @@
1
+ require 'prometheus/client/helper/mmaped_file'
1
2
  require 'prometheus/client'
2
- require 'mmap'
3
3
 
4
4
  module Prometheus
5
5
  module Client
@@ -13,36 +13,34 @@ module Prometheus
13
13
  # There's then a number of entries, consisting of a 4 byte int which is the
14
14
  # size of the next field, a utf-8 encoded string key, padding to an 8 byte
15
15
  # alignment, and then a 8 byte float which is the value.
16
- #
17
- # TODO(julius): dealing with Mmap.new, truncate etc. errors?
18
16
  class MmapedDict
19
- MINIMUM_SIZE = 4.freeze
20
- attr_reader :m, :capacity, :used, :positions
17
+ MINIMUM_SIZE = 8
18
+ attr_reader :m, :used, :positions
21
19
 
22
- def initialize(filename)
20
+ def initialize(m)
23
21
  @mutex = Mutex.new
24
- @f = File.open(filename, 'a+b')
25
- process_file
22
+
23
+ @m = m
24
+ # @m.mlock # TODO: Ensure memory is locked to RAM
25
+
26
+ @used = @m.used
27
+
28
+ @positions = {}
29
+ read_all_positions.each do |key, _, pos|
30
+ @positions[key] = pos
31
+ end
26
32
  rescue StandardError => e
27
- raise ParsingError, "exception #{e} while processing metrics file #{@f.path}"
33
+ raise ParsingError, "exception #{e} while processing metrics file #{path}"
28
34
  end
29
35
 
30
36
  # Yield (key, value). No locking is performed.
31
37
  def self.read_all_values(f)
32
- m = Mmap.new(f, 'rw', Mmap::MAP_SHARED)
33
- used, = m[0..3].unpack('l')
34
- pos = 8
35
- values = []
36
- while pos < used
37
- data = m.slice(pos..-1)
38
- encoded_len, = data.unpack('l')
39
- value_offset = 4 + encoded_len + (8 - (encoded_len + 4) % 8)
38
+ m = Helper::MmapedFile.open(f)
40
39
 
40
+ m.entries.map do |data, encoded_len, value_offset|
41
41
  encoded, value = data.unpack(format('@4A%d@%dd', encoded_len, value_offset))
42
- values << [encoded, value]
43
- pos += value_offset + 8
42
+ [encoded, value]
44
43
  end
45
- values
46
44
  ensure
47
45
  m.munmap
48
46
  end
@@ -66,15 +64,13 @@ module Prometheus
66
64
  end
67
65
 
68
66
  def path
69
- @f.path unless @f.nil?
67
+ @m.filepath unless @m.nil?
70
68
  end
71
69
 
72
70
  def close
73
- @m.munmap
71
+ @m.close
74
72
  rescue TypeError => e
75
73
  Prometheus::Client.logger.warn("munmap raised error #{e}")
76
- ensure
77
- @f.close
78
74
  end
79
75
 
80
76
  def initial_mmap_file_size
@@ -83,58 +79,22 @@ module Prometheus
83
79
 
84
80
  private
85
81
 
86
- def process_file
87
- @f.truncate(initial_mmap_file_size) if @f.size < MINIMUM_SIZE
88
-
89
- @capacity = @f.size
90
- @m = Mmap.new(@f.path, 'rw', Mmap::MAP_SHARED)
91
- # @m.mlock # TODO: Why does this raise an error?
92
-
93
- @positions = {}
94
- @used = @m[0..3].unpack('l')[0]
95
- if @used == 0
96
- @used = 8
97
- @m[0..3] = [@used].pack('l')
98
- else
99
- read_all_positions.each do |key, _, pos|
100
- @positions[key] = pos
101
- end
102
- end
103
- end
104
-
105
82
  # Initialize a value. Lock must be held by caller.
106
83
  def init_value(key)
107
- # Pad to be 8-byte aligned.
108
- padded = key + (' ' * (8 - (key.length + 4) % 8))
109
- value = [key.length, padded, 0.0].pack("lA#{padded.length}d")
110
- while @used + value.length > @capacity
111
- @capacity *= 2
112
- @f.truncate(@capacity)
113
- @m.unmap
114
- @m = Mmap.new(@f.path, 'rw', Mmap::MAP_SHARED)
115
- end
116
- @m[@used..@used + value.length] = value
84
+ @m.add_entry(key, 0.0)
117
85
 
118
86
  # Update how much space we've used.
119
- @used += value.length
120
- @m[0..3] = [@used].pack('l')
87
+ @used = @m.used
88
+
121
89
  @positions[key] = @used - 8
122
90
  end
123
91
 
124
92
  # Yield (key, value, pos). No locking is performed.
125
93
  def read_all_positions
126
- pos = 8
127
- values = []
128
- while pos < @used
129
- data = @m.slice(pos..-1)
130
- encoded_len = data.unpack('l')[0]
131
- padding_len = 8 - (encoded_len + 4) % 8
132
- encoded = data.unpack(format('@4A%d', encoded_len))
133
- pos += 4 + encoded_len + padding_len
134
- values << [encoded, pos]
135
- pos += 8
94
+ @m.entries.map do |data, encoded_len, value_offset|
95
+ encoded, = data.unpack(format('@4A%d', encoded_len))
96
+ [encoded, value_offset]
136
97
  end
137
- values
138
98
  end
139
99
  end
140
100
  end
@@ -81,12 +81,11 @@ module Prometheus
81
81
  @@files_lock.synchronize do
82
82
  unless @@files.has_key?(@file_prefix)
83
83
  unless @file.nil?
84
- puts @file
85
84
  @file.close
86
85
  end
86
+ mmaped_file = Helper::MmapedFile.open_process_exclusive_file(@file_prefix)
87
87
 
88
- filename = File.join(Prometheus::Client.configuration.multiprocess_files_dir, "#{@file_prefix}_#{@@pid}.db")
89
- @@files[@file_prefix] = MmapedDict.new(filename)
88
+ @@files[@file_prefix] = MmapedDict.new(mmaped_file)
90
89
  end
91
90
  end
92
91
 
@@ -110,12 +109,15 @@ module Prometheus
110
109
  @file.write_value(key, val)
111
110
  rescue StandardError => e
112
111
  Prometheus::Client.logger.warn("writing value to #{@file.path} failed with #{e}")
112
+ Prometheus::Client.logger.debug(e.backtrace.join("\n"))
113
113
  end
114
114
 
115
115
  def read_value(key)
116
116
  @file.read_value(key)
117
117
  rescue StandardError => e
118
118
  Prometheus::Client.logger.warn("reading value from #{@file.path} failed with #{e}")
119
+ Prometheus::Client.logger.debug(e.backtrace.join("\n"))
120
+ 0
119
121
  end
120
122
  end
121
123
  end
@@ -4,7 +4,7 @@ require 'mmap'
4
4
  module Prometheus
5
5
  module Client
6
6
  class SimpleValue
7
- def initialize(type, metric_name, name, labels, value = 0)
7
+ def initialize(type, metric_name, name, labels, value = 0.0)
8
8
  @value = value
9
9
  end
10
10
 
@@ -46,7 +46,7 @@ module Prometheus
46
46
  @validator.valid?(labels)
47
47
 
48
48
  synchronize do
49
- @values[labels].sum
49
+ @values[labels].sum.get
50
50
  end
51
51
  end
52
52
 
@@ -4,9 +4,12 @@ module Prometheus
4
4
  module Unicorn
5
5
  def self.worker_pid_provider
6
6
  wid = worker_id
7
- Process.pid if wid.nil?
8
-
9
- "worker_id_#{wid}"
7
+ wid = Process.pid if wid.nil?
8
+ if wid.nil?
9
+ "process_pid_#{Process.pid}"
10
+ else
11
+ "worker_id_#{wid}"
12
+ end
10
13
  end
11
14
 
12
15
  def self.worker_id
@@ -11,7 +11,7 @@ module Prometheus
11
11
  def value_object(type, metric_name, name, labels, *args)
12
12
  value_class.new(type, metric_name, name, labels, *args)
13
13
  rescue StandardError => e
14
- Prometheus::Client.logger.info("error #{e} while creating instance of #{value_class} defaultig to SimpleValue")
14
+ Prometheus::Client.logger.info("error #{e} while creating instance of #{value_class} defaulting to SimpleValue")
15
15
  Prometheus::Client::SimpleValue.new(type, metric_name, name, labels)
16
16
  end
17
17
  end
@@ -1,5 +1,5 @@
1
1
  module Prometheus
2
2
  module Client
3
- VERSION = '0.7.0.beta14'
3
+ VERSION = '0.7.0.beta15'
4
4
  end
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: prometheus-client-mmap
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.0.beta14
4
+ version: 0.7.0.beta15
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tobias Schmidt
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-08-29 00:00:00.000000000 Z
11
+ date: 2017-10-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: mmap2
@@ -45,6 +45,7 @@ files:
45
45
  - lib/prometheus/client/formats/text.rb
46
46
  - lib/prometheus/client/gauge.rb
47
47
  - lib/prometheus/client/helper/json_parser.rb
48
+ - lib/prometheus/client/helper/mmaped_file.rb
48
49
  - lib/prometheus/client/histogram.rb
49
50
  - lib/prometheus/client/label_set_validator.rb
50
51
  - lib/prometheus/client/metric.rb