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 +4 -4
- data/lib/prometheus/client/formats/text.rb +1 -0
- data/lib/prometheus/client/helper/mmaped_file.rb +150 -0
- data/lib/prometheus/client/mmaped_dict.rb +26 -66
- data/lib/prometheus/client/mmaped_value.rb +5 -3
- data/lib/prometheus/client/simple_value.rb +1 -1
- data/lib/prometheus/client/summary.rb +1 -1
- data/lib/prometheus/client/support/unicorn.rb +6 -3
- data/lib/prometheus/client/uses_value_type.rb +1 -1
- data/lib/prometheus/client/version.rb +1 -1
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 84f31b1815d567cd2d00583255372973f739fad7
|
4
|
+
data.tar.gz: b2752140fb46a42db2081099a42943d33dc890d5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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 =
|
20
|
-
attr_reader :m, :
|
17
|
+
MINIMUM_SIZE = 8
|
18
|
+
attr_reader :m, :used, :positions
|
21
19
|
|
22
|
-
def initialize(
|
20
|
+
def initialize(m)
|
23
21
|
@mutex = Mutex.new
|
24
|
-
|
25
|
-
|
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 #{
|
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 =
|
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
|
-
|
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
|
-
@
|
67
|
+
@m.filepath unless @m.nil?
|
70
68
|
end
|
71
69
|
|
72
70
|
def close
|
73
|
-
@m.
|
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
|
-
|
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
|
120
|
-
|
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
|
-
|
127
|
-
|
128
|
-
|
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
|
-
|
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,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
|
-
|
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}
|
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
|
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.
|
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-
|
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
|