prometheus-client-mmap 0.19.1 → 0.21.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,49 @@ 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 load_rust_extension
50
+ begin
51
+ ruby_version = /(\d+\.\d+)/.match(RUBY_VERSION)
52
+ require_relative "../../../#{ruby_version}/fast_mmaped_file_rs"
53
+ rescue LoadError
54
+ require 'fast_mmaped_file_rs'
55
+ end
56
+ end
57
+
58
+ def check_for_rust
59
+ # This will be evaluated on each invocation even with `||=` if
60
+ # `@rust_available` if false. Running a `require` statement is slow,
61
+ # so the `rust_impl_available?` method memoizes the result, external
62
+ # callers can only trigger this method a single time.
63
+ @rust_available = begin
64
+ load_rust_extension
65
+ true
66
+ rescue LoadError
67
+ Prometheus::Client.logger.info('FastMmapedFileRs unavailable')
68
+ false
69
+ end
70
+ end
71
+
39
72
  def load_metrics(path)
40
73
  metrics = {}
41
74
  Dir.glob(File.join(path, '*.db')).sort.each do |f|
@@ -1,6 +1,13 @@
1
1
  require 'prometheus/client/helper/entry_parser'
2
2
  require 'prometheus/client/helper/file_locker'
3
- require 'fast_mmaped_file'
3
+
4
+ # load precompiled extension if available
5
+ begin
6
+ ruby_version = /(\d+\.\d+)/.match(RUBY_VERSION)
7
+ require_relative "../../../#{ruby_version}/fast_mmaped_file"
8
+ rescue LoadError
9
+ require 'fast_mmaped_file'
10
+ end
4
11
 
5
12
  module Prometheus
6
13
  module Client
@@ -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.21.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,16 +1,30 @@
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.21.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tobias Schmidt
8
8
  - Paweł Chojnacki
9
- autorequire:
9
+ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2023-03-17 00:00:00.000000000 Z
12
+ date: 2023-04-21 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
@@ -65,14 +79,28 @@ dependencies:
65
79
  requirements:
66
80
  - - "~>"
67
81
  - !ruby/object:Gem::Version
68
- version: '1'
82
+ version: 1.2.1
69
83
  type: :development
70
84
  prerelease: false
71
85
  version_requirements: !ruby/object:Gem::Requirement
72
86
  requirements:
73
87
  - - "~>"
74
88
  - !ruby/object:Gem::Version
75
- version: '1'
89
+ version: 1.2.1
90
+ - !ruby/object:Gem::Dependency
91
+ name: rake-compiler-dock
92
+ requirement: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: 1.3.0
97
+ type: :development
98
+ prerelease: false
99
+ version_requirements: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: 1.3.0
76
104
  - !ruby/object:Gem::Dependency
77
105
  name: ruby-prof
78
106
  requirement: !ruby/object:Gem::Requirement
@@ -87,13 +115,14 @@ dependencies:
87
115
  - - "~>"
88
116
  - !ruby/object:Gem::Version
89
117
  version: 0.16.2
90
- description:
118
+ description:
91
119
  email:
92
120
  - ts@soundcloud.com
93
121
  - pawel@gitlab.com
94
122
  executables: []
95
123
  extensions:
96
124
  - ext/fast_mmaped_file/extconf.rb
125
+ - ext/fast_mmaped_file_rs/extconf.rb
97
126
  extra_rdoc_files: []
98
127
  files:
99
128
  - README.md
@@ -114,6 +143,22 @@ files:
114
143
  - ext/fast_mmaped_file/utils.h
115
144
  - ext/fast_mmaped_file/value_access.c
116
145
  - ext/fast_mmaped_file/value_access.h
146
+ - ext/fast_mmaped_file_rs/.cargo/config.toml
147
+ - ext/fast_mmaped_file_rs/Cargo.lock
148
+ - ext/fast_mmaped_file_rs/Cargo.toml
149
+ - ext/fast_mmaped_file_rs/README.md
150
+ - ext/fast_mmaped_file_rs/extconf.rb
151
+ - ext/fast_mmaped_file_rs/src/error.rs
152
+ - ext/fast_mmaped_file_rs/src/file_entry.rs
153
+ - ext/fast_mmaped_file_rs/src/file_info.rs
154
+ - ext/fast_mmaped_file_rs/src/lib.rs
155
+ - ext/fast_mmaped_file_rs/src/macros.rs
156
+ - ext/fast_mmaped_file_rs/src/map.rs
157
+ - ext/fast_mmaped_file_rs/src/mmap.rs
158
+ - ext/fast_mmaped_file_rs/src/parser.rs
159
+ - ext/fast_mmaped_file_rs/src/raw_entry.rs
160
+ - ext/fast_mmaped_file_rs/src/testhelper.rs
161
+ - ext/fast_mmaped_file_rs/src/util.rs
117
162
  - lib/prometheus.rb
118
163
  - lib/prometheus/client.rb
119
164
  - lib/prometheus/client/configuration.rb
@@ -132,6 +177,7 @@ files:
132
177
  - lib/prometheus/client/metric.rb
133
178
  - lib/prometheus/client/mmaped_dict.rb
134
179
  - lib/prometheus/client/mmaped_value.rb
180
+ - lib/prometheus/client/page_size.rb
135
181
  - lib/prometheus/client/push.rb
136
182
  - lib/prometheus/client/rack/collector.rb
137
183
  - lib/prometheus/client/rack/exporter.rb
@@ -141,6 +187,7 @@ files:
141
187
  - lib/prometheus/client/support/unicorn.rb
142
188
  - lib/prometheus/client/uses_value_type.rb
143
189
  - lib/prometheus/client/version.rb
190
+ - vendor/c/hashmap/.gitignore
144
191
  - vendor/c/hashmap/LICENSE
145
192
  - vendor/c/hashmap/README.md
146
193
  - vendor/c/hashmap/_config.yml
@@ -148,6 +195,7 @@ files:
148
195
  - vendor/c/hashmap/src/hashmap.h
149
196
  - vendor/c/hashmap/test/Makefile
150
197
  - vendor/c/hashmap/test/hashmap_test.c
198
+ - vendor/c/jsmn/.travis.yml
151
199
  - vendor/c/jsmn/LICENSE
152
200
  - vendor/c/jsmn/Makefile
153
201
  - vendor/c/jsmn/README.md
@@ -163,7 +211,7 @@ homepage: https://gitlab.com/gitlab-org/prometheus-client-mmap
163
211
  licenses:
164
212
  - Apache-2.0
165
213
  metadata: {}
166
- post_install_message:
214
+ post_install_message:
167
215
  rdoc_options: []
168
216
  require_paths:
169
217
  - lib
@@ -176,10 +224,10 @@ required_rubygems_version: !ruby/object:Gem::Requirement
176
224
  requirements:
177
225
  - - ">="
178
226
  - !ruby/object:Gem::Version
179
- version: '0'
227
+ version: 3.3.22
180
228
  requirements: []
181
- rubygems_version: 3.4.8
182
- signing_key:
229
+ rubygems_version: 3.3.26
230
+ signing_key:
183
231
  specification_version: 4
184
232
  summary: A suite of instrumentation metric primitivesthat can be exposed through a
185
233
  web services interface.