prometheus-client-mmap 0.19.1 → 0.20.0

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.
@@ -0,0 +1,121 @@
1
+ use nix::errno::Errno;
2
+ use nix::libc::c_long;
3
+ use std::fmt::Display;
4
+ use std::io;
5
+ use std::mem::size_of;
6
+
7
+ use crate::error::MmapError;
8
+ use crate::Result;
9
+
10
+ /// Wrapper around `checked_add()` that converts failures
11
+ /// to `MmapError::Overflow`.
12
+ pub trait CheckedOps: Sized {
13
+ fn add_chk(self, rhs: Self) -> Result<Self>;
14
+ fn mul_chk(self, rhs: Self) -> Result<Self>;
15
+ }
16
+
17
+ impl CheckedOps for usize {
18
+ fn add_chk(self, rhs: Self) -> Result<Self> {
19
+ self.checked_add(rhs)
20
+ .ok_or_else(|| MmapError::overflowed(self, rhs, "adding"))
21
+ }
22
+
23
+ fn mul_chk(self, rhs: Self) -> Result<Self> {
24
+ self.checked_mul(rhs)
25
+ .ok_or_else(|| MmapError::overflowed(self, rhs, "multiplying"))
26
+ }
27
+ }
28
+
29
+ impl CheckedOps for c_long {
30
+ fn add_chk(self, rhs: Self) -> Result<Self> {
31
+ self.checked_add(rhs)
32
+ .ok_or_else(|| MmapError::overflowed(self, rhs, "adding"))
33
+ }
34
+
35
+ fn mul_chk(self, rhs: Self) -> Result<Self> {
36
+ self.checked_mul(rhs)
37
+ .ok_or_else(|| MmapError::overflowed(self, rhs, "multiplying"))
38
+ }
39
+ }
40
+
41
+ /// A wrapper around `TryFrom`, returning `MmapError::FailedCast` on error.
42
+ pub fn cast_chk<T, U>(val: T, name: &str) -> Result<U>
43
+ where
44
+ T: Copy + Display,
45
+ U: std::convert::TryFrom<T>,
46
+ {
47
+ U::try_from(val).map_err(|_| MmapError::failed_cast::<T, U>(val, name))
48
+ }
49
+
50
+ /// Retrieve errno(3).
51
+ pub fn errno() -> i32 {
52
+ // UNWRAP: This will always return `Some` when called from `last_os_error()`.
53
+ io::Error::last_os_error().raw_os_error().unwrap()
54
+ }
55
+
56
+ /// Get the error string associated with errno(3).
57
+ /// Equivalent to strerror(3).
58
+ pub fn strerror(errno: i32) -> &'static str {
59
+ Errno::from_i32(errno).desc()
60
+ }
61
+
62
+ /// Read a `u32` value from a byte slice starting from `offset`.
63
+ #[inline]
64
+ pub fn read_u32(buf: &[u8], offset: usize) -> Result<u32> {
65
+ if let Some(slice) = buf.get(offset..offset + size_of::<u32>()) {
66
+ // UNWRAP: We can safely unwrap the conversion from slice to array as we
67
+ // the source and targets are constructed here with the same length.
68
+ let out: &[u8; size_of::<u32>()] = slice.try_into().unwrap();
69
+
70
+ return Ok(u32::from_ne_bytes(*out));
71
+ }
72
+ Err(MmapError::out_of_bounds(offset, buf.len()))
73
+ }
74
+
75
+ /// Read an `f64` value from a byte slice starting from `offset`.
76
+ #[inline]
77
+ pub fn read_f64(buf: &[u8], offset: usize) -> Result<f64> {
78
+ if let Some(slice) = buf.get(offset..offset + size_of::<f64>()) {
79
+ // UNWRAP: We can safely unwrap the conversion from slice to array as we
80
+ // can be sure the target array has same length as the source slice.
81
+ let out: &[u8; size_of::<f64>()] = slice.try_into().unwrap();
82
+
83
+ return Ok(f64::from_ne_bytes(*out));
84
+ }
85
+ Err(MmapError::out_of_bounds(
86
+ offset + size_of::<f64>(),
87
+ buf.len(),
88
+ ))
89
+ }
90
+
91
+ #[cfg(test)]
92
+ mod test {
93
+ use super::*;
94
+
95
+ #[test]
96
+ fn test_read_u32() {
97
+ let buf = 1u32.to_ne_bytes();
98
+
99
+ assert!(matches!(read_u32(&buf, 0), Ok(1)), "index ok");
100
+ assert!(read_u32(&buf, 10).is_err(), "index out of range");
101
+ assert!(
102
+ read_u32(&buf, 1).is_err(),
103
+ "index in range but end out of range"
104
+ );
105
+ }
106
+
107
+ #[test]
108
+ fn test_read_f64() {
109
+ let buf = 1.00f64.to_ne_bytes();
110
+
111
+ let ok = read_f64(&buf, 0);
112
+ assert!(ok.is_ok());
113
+ assert_eq!(ok.unwrap(), 1.00);
114
+
115
+ assert!(read_f64(&buf, 10).is_err(), "index out of range");
116
+ assert!(
117
+ read_f64(&buf, 1).is_err(),
118
+ "index in range but end out of range"
119
+ );
120
+ }
121
+ }
@@ -1,5 +1,6 @@
1
1
  require 'prometheus/client/registry'
2
2
  require 'prometheus/client/mmaped_value'
3
+ require 'prometheus/client/page_size'
3
4
  require 'logger'
4
5
  require 'tmpdir'
5
6
 
@@ -10,7 +11,7 @@ module Prometheus
10
11
 
11
12
  def initialize
12
13
  @value_class = ::Prometheus::Client::MmapedValue
13
- @initial_mmap_file_size = 4 * 1024
14
+ @initial_mmap_file_size = ::Prometheus::Client::PageSize.page_size(fallback_page_size: 4096)
14
15
  @logger = Logger.new($stdout)
15
16
  @pid_provider = Process.method(:pid)
16
17
  @multiprocess_files_dir = ENV.fetch('prometheus_multiproc_dir') do
@@ -26,16 +26,40 @@ module Prometheus
26
26
  Helper::MetricsRepresentation.to_text(metrics)
27
27
  end
28
28
 
29
- def marshal_multiprocess(path = Prometheus::Client.configuration.multiprocess_files_dir)
29
+ def marshal_multiprocess(path = Prometheus::Client.configuration.multiprocess_files_dir, use_rust: false)
30
30
  file_list = Dir.glob(File.join(path, '*.db')).sort
31
31
  .map {|f| Helper::PlainFile.new(f) }
32
32
  .map {|f| [f.filepath, f.multiprocess_mode.to_sym, f.type.to_sym, f.pid] }
33
33
 
34
- FastMmapedFile.to_metrics(file_list.to_a)
34
+ if use_rust && rust_impl_available?
35
+ FastMmapedFileRs.to_metrics(file_list.to_a)
36
+ else
37
+ FastMmapedFile.to_metrics(file_list.to_a)
38
+ end
39
+ end
40
+
41
+ def rust_impl_available?
42
+ return @rust_available unless @rust_available.nil?
43
+
44
+ check_for_rust
35
45
  end
36
46
 
37
47
  private
38
48
 
49
+ def check_for_rust
50
+ # This will be evaluated on each invocation even with `||=` if
51
+ # `@rust_available` if false. Running a `require` statement is slow,
52
+ # so the `rust_impl_available?` method memoizes the result, external
53
+ # callers can only trigger this method a single time.
54
+ @rust_available = begin
55
+ require 'fast_mmaped_file_rs'
56
+ true
57
+ rescue LoadError
58
+ Prometheus::Client.logger.info('FastMmapedFileRs unavailable')
59
+ false
60
+ end
61
+ end
62
+
39
63
  def load_metrics(path)
40
64
  metrics = {}
41
65
  Dir.glob(File.join(path, '*.db')).sort.each do |f|
@@ -0,0 +1,17 @@
1
+ require 'open3'
2
+
3
+ module Prometheus
4
+ module Client
5
+ module PageSize
6
+ def self.page_size(fallback_page_size: 4096)
7
+ stdout, status = Open3.capture2('getconf PAGESIZE')
8
+ return fallback_page_size if status.nil? || !status.success?
9
+
10
+ page_size = stdout.chomp.to_i
11
+ return fallback_page_size if page_size <= 0
12
+
13
+ page_size
14
+ end
15
+ end
16
+ end
17
+ end
@@ -1,5 +1,5 @@
1
1
  module Prometheus
2
2
  module Client
3
- VERSION = '0.19.1'.freeze
3
+ VERSION = '0.20.0'.freeze
4
4
  end
5
5
  end
@@ -0,0 +1,52 @@
1
+ # Prerequisites
2
+ *.d
3
+
4
+ # Object files
5
+ *.o
6
+ *.ko
7
+ *.obj
8
+ *.elf
9
+
10
+ # Linker output
11
+ *.ilk
12
+ *.map
13
+ *.exp
14
+
15
+ # Precompiled Headers
16
+ *.gch
17
+ *.pch
18
+
19
+ # Libraries
20
+ *.lib
21
+ *.a
22
+ *.la
23
+ *.lo
24
+
25
+ # Shared objects (inc. Windows DLLs)
26
+ *.dll
27
+ *.so
28
+ *.so.*
29
+ *.dylib
30
+
31
+ # Executables
32
+ *.exe
33
+ *.out
34
+ *.app
35
+ *.i*86
36
+ *.x86_64
37
+ *.hex
38
+
39
+ # Debug files
40
+ *.dSYM/
41
+ *.su
42
+ *.idb
43
+ *.pdb
44
+
45
+ # Kernel Module Compile Results
46
+ *.mod*
47
+ *.cmd
48
+ .tmp_versions/
49
+ modules.order
50
+ Module.symvers
51
+ Mkfile.old
52
+ dkms.conf
@@ -0,0 +1,4 @@
1
+ language: c
2
+ sudo: false
3
+ script:
4
+ - make test
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: prometheus-client-mmap
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.19.1
4
+ version: 0.20.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tobias Schmidt
@@ -9,8 +9,22 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2023-03-17 00:00:00.000000000 Z
12
+ date: 2023-04-13 00:00:00.000000000 Z
13
13
  dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rb_sys
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - "~>"
19
+ - !ruby/object:Gem::Version
20
+ version: '0.9'
21
+ type: :runtime
22
+ prerelease: false
23
+ version_requirements: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - "~>"
26
+ - !ruby/object:Gem::Version
27
+ version: '0.9'
14
28
  - !ruby/object:Gem::Dependency
15
29
  name: fuzzbert
16
30
  requirement: !ruby/object:Gem::Requirement
@@ -94,6 +108,7 @@ email:
94
108
  executables: []
95
109
  extensions:
96
110
  - ext/fast_mmaped_file/extconf.rb
111
+ - ext/fast_mmaped_file_rs/extconf.rb
97
112
  extra_rdoc_files: []
98
113
  files:
99
114
  - README.md
@@ -114,6 +129,23 @@ files:
114
129
  - ext/fast_mmaped_file/utils.h
115
130
  - ext/fast_mmaped_file/value_access.c
116
131
  - ext/fast_mmaped_file/value_access.h
132
+ - ext/fast_mmaped_file_rs/.cargo/config.toml
133
+ - ext/fast_mmaped_file_rs/.tool-versions
134
+ - ext/fast_mmaped_file_rs/Cargo.lock
135
+ - ext/fast_mmaped_file_rs/Cargo.toml
136
+ - ext/fast_mmaped_file_rs/README.md
137
+ - ext/fast_mmaped_file_rs/extconf.rb
138
+ - ext/fast_mmaped_file_rs/src/error.rs
139
+ - ext/fast_mmaped_file_rs/src/file_entry.rs
140
+ - ext/fast_mmaped_file_rs/src/file_info.rs
141
+ - ext/fast_mmaped_file_rs/src/lib.rs
142
+ - ext/fast_mmaped_file_rs/src/macros.rs
143
+ - ext/fast_mmaped_file_rs/src/map.rs
144
+ - ext/fast_mmaped_file_rs/src/mmap.rs
145
+ - ext/fast_mmaped_file_rs/src/parser.rs
146
+ - ext/fast_mmaped_file_rs/src/raw_entry.rs
147
+ - ext/fast_mmaped_file_rs/src/testhelper.rs
148
+ - ext/fast_mmaped_file_rs/src/util.rs
117
149
  - lib/prometheus.rb
118
150
  - lib/prometheus/client.rb
119
151
  - lib/prometheus/client/configuration.rb
@@ -132,6 +164,7 @@ files:
132
164
  - lib/prometheus/client/metric.rb
133
165
  - lib/prometheus/client/mmaped_dict.rb
134
166
  - lib/prometheus/client/mmaped_value.rb
167
+ - lib/prometheus/client/page_size.rb
135
168
  - lib/prometheus/client/push.rb
136
169
  - lib/prometheus/client/rack/collector.rb
137
170
  - lib/prometheus/client/rack/exporter.rb
@@ -141,6 +174,7 @@ files:
141
174
  - lib/prometheus/client/support/unicorn.rb
142
175
  - lib/prometheus/client/uses_value_type.rb
143
176
  - lib/prometheus/client/version.rb
177
+ - vendor/c/hashmap/.gitignore
144
178
  - vendor/c/hashmap/LICENSE
145
179
  - vendor/c/hashmap/README.md
146
180
  - vendor/c/hashmap/_config.yml
@@ -148,6 +182,7 @@ files:
148
182
  - vendor/c/hashmap/src/hashmap.h
149
183
  - vendor/c/hashmap/test/Makefile
150
184
  - vendor/c/hashmap/test/hashmap_test.c
185
+ - vendor/c/jsmn/.travis.yml
151
186
  - vendor/c/jsmn/LICENSE
152
187
  - vendor/c/jsmn/Makefile
153
188
  - vendor/c/jsmn/README.md
@@ -178,7 +213,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
178
213
  - !ruby/object:Gem::Version
179
214
  version: '0'
180
215
  requirements: []
181
- rubygems_version: 3.4.8
216
+ rubygems_version: 3.4.10
182
217
  signing_key:
183
218
  specification_version: 4
184
219
  summary: A suite of instrumentation metric primitivesthat can be exposed through a