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

Sign up to get free protection for your applications and to get access to all the features.
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