vinted-prometheus-client-mmap 1.5.0-x86_64-linux

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.
Files changed (57) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +5 -0
  3. data/ext/fast_mmaped_file_rs/Cargo.toml +40 -0
  4. data/ext/fast_mmaped_file_rs/README.md +52 -0
  5. data/ext/fast_mmaped_file_rs/build.rs +7 -0
  6. data/ext/fast_mmaped_file_rs/extconf.rb +28 -0
  7. data/ext/fast_mmaped_file_rs/src/error.rs +174 -0
  8. data/ext/fast_mmaped_file_rs/src/exemplars.rs +25 -0
  9. data/ext/fast_mmaped_file_rs/src/file_entry.rs +1252 -0
  10. data/ext/fast_mmaped_file_rs/src/file_info.rs +240 -0
  11. data/ext/fast_mmaped_file_rs/src/lib.rs +89 -0
  12. data/ext/fast_mmaped_file_rs/src/macros.rs +14 -0
  13. data/ext/fast_mmaped_file_rs/src/map.rs +519 -0
  14. data/ext/fast_mmaped_file_rs/src/metrics.proto +153 -0
  15. data/ext/fast_mmaped_file_rs/src/mmap/inner.rs +775 -0
  16. data/ext/fast_mmaped_file_rs/src/mmap.rs +977 -0
  17. data/ext/fast_mmaped_file_rs/src/raw_entry.rs +547 -0
  18. data/ext/fast_mmaped_file_rs/src/testhelper.rs +222 -0
  19. data/ext/fast_mmaped_file_rs/src/util.rs +140 -0
  20. data/lib/.DS_Store +0 -0
  21. data/lib/2.7/fast_mmaped_file_rs.so +0 -0
  22. data/lib/3.0/fast_mmaped_file_rs.so +0 -0
  23. data/lib/3.1/fast_mmaped_file_rs.so +0 -0
  24. data/lib/3.2/fast_mmaped_file_rs.so +0 -0
  25. data/lib/3.3/fast_mmaped_file_rs.so +0 -0
  26. data/lib/prometheus/.DS_Store +0 -0
  27. data/lib/prometheus/client/configuration.rb +24 -0
  28. data/lib/prometheus/client/counter.rb +27 -0
  29. data/lib/prometheus/client/formats/protobuf.rb +93 -0
  30. data/lib/prometheus/client/formats/text.rb +85 -0
  31. data/lib/prometheus/client/gauge.rb +40 -0
  32. data/lib/prometheus/client/helper/entry_parser.rb +132 -0
  33. data/lib/prometheus/client/helper/file_locker.rb +50 -0
  34. data/lib/prometheus/client/helper/json_parser.rb +23 -0
  35. data/lib/prometheus/client/helper/metrics_processing.rb +45 -0
  36. data/lib/prometheus/client/helper/metrics_representation.rb +51 -0
  37. data/lib/prometheus/client/helper/mmaped_file.rb +64 -0
  38. data/lib/prometheus/client/helper/plain_file.rb +29 -0
  39. data/lib/prometheus/client/histogram.rb +80 -0
  40. data/lib/prometheus/client/label_set_validator.rb +85 -0
  41. data/lib/prometheus/client/metric.rb +80 -0
  42. data/lib/prometheus/client/mmaped_dict.rb +83 -0
  43. data/lib/prometheus/client/mmaped_value.rb +164 -0
  44. data/lib/prometheus/client/page_size.rb +17 -0
  45. data/lib/prometheus/client/push.rb +203 -0
  46. data/lib/prometheus/client/rack/collector.rb +88 -0
  47. data/lib/prometheus/client/rack/exporter.rb +102 -0
  48. data/lib/prometheus/client/registry.rb +65 -0
  49. data/lib/prometheus/client/simple_value.rb +31 -0
  50. data/lib/prometheus/client/summary.rb +69 -0
  51. data/lib/prometheus/client/support/puma.rb +44 -0
  52. data/lib/prometheus/client/support/unicorn.rb +35 -0
  53. data/lib/prometheus/client/uses_value_type.rb +20 -0
  54. data/lib/prometheus/client/version.rb +5 -0
  55. data/lib/prometheus/client.rb +58 -0
  56. data/lib/prometheus.rb +3 -0
  57. metadata +210 -0
@@ -0,0 +1,240 @@
1
+ use magnus::exception::*;
2
+ use magnus::{Error, RString, Symbol, Value};
3
+ use std::ffi::OsString;
4
+ use std::fs::File;
5
+ use std::io::{self, Read, Seek};
6
+ use std::os::unix::ffi::OsStringExt;
7
+ use std::path::PathBuf;
8
+
9
+ use crate::err;
10
+ use crate::error::{MmapError, RubyError};
11
+ use crate::util;
12
+ use crate::Result;
13
+
14
+ /// The details of a `*.db` file.
15
+ #[derive(Debug)]
16
+ pub struct FileInfo {
17
+ pub file: File,
18
+ pub path: PathBuf,
19
+ pub len: usize,
20
+ pub multiprocess_mode: Symbol,
21
+ pub type_: Symbol,
22
+ pub pid: String,
23
+ }
24
+
25
+ impl FileInfo {
26
+ /// Receive the details of a file from Ruby and store as a `FileInfo`.
27
+ pub fn open_from_params(params: &[Value; 4]) -> magnus::error::Result<Self> {
28
+ if params.len() != 4 {
29
+ return Err(err!(
30
+ arg_error(),
31
+ "wrong number of arguments {} instead of 4",
32
+ params.len()
33
+ ));
34
+ }
35
+
36
+ let filepath = RString::from_value(params[0])
37
+ .ok_or_else(|| err!(arg_error(), "can't convert filepath to String"))?;
38
+
39
+ // SAFETY: We immediately copy the string buffer from Ruby, preventing
40
+ // it from being mutated out from under us.
41
+ let path_bytes: Vec<_> = unsafe { filepath.as_slice().to_owned() };
42
+ let path = PathBuf::from(OsString::from_vec(path_bytes));
43
+
44
+ let mut file = File::open(&path).map_err(|_| {
45
+ err!(
46
+ arg_error(),
47
+ "Can't open {}, errno: {}",
48
+ path.display(),
49
+ util::errno()
50
+ )
51
+ })?;
52
+
53
+ let stat = file
54
+ .metadata()
55
+ .map_err(|_| err!(io_error(), "Can't stat file, errno: {}", util::errno()))?;
56
+
57
+ let length = util::cast_chk::<_, usize>(stat.len(), "file size")?;
58
+
59
+ let multiprocess_mode = Symbol::from_value(params[1])
60
+ .ok_or_else(|| err!(arg_error(), "expected multiprocess_mode to be a symbol"))?;
61
+
62
+ let type_ = Symbol::from_value(params[2])
63
+ .ok_or_else(|| err!(arg_error(), "expected file type to be a symbol"))?;
64
+
65
+ let pid = RString::from_value(params[3])
66
+ .ok_or_else(|| err!(arg_error(), "expected pid to be a String"))?;
67
+
68
+ file.rewind()
69
+ .map_err(|_| err!(io_error(), "Can't fseek 0, errno: {}", util::errno()))?;
70
+
71
+ Ok(Self {
72
+ file,
73
+ path,
74
+ len: length,
75
+ multiprocess_mode,
76
+ type_,
77
+ pid: pid.to_string()?,
78
+ })
79
+ }
80
+
81
+ /// Read the contents of the associated file into the buffer provided by
82
+ /// the caller.
83
+ pub fn read_from_file(&mut self, buf: &mut Vec<u8>) -> Result<()> {
84
+ buf.clear();
85
+ buf.try_reserve(self.len).map_err(|_| {
86
+ MmapError::legacy(
87
+ format!("Can't malloc {}, errno: {}", self.len, util::errno()),
88
+ RubyError::Io,
89
+ )
90
+ })?;
91
+
92
+ match self.file.read_to_end(buf) {
93
+ Ok(n) if n == self.len => Ok(()),
94
+ // A worker may expand the file between our `stat` and `read`, no harm done.
95
+ Ok(n) if n > self.len => {
96
+ self.len = n;
97
+ Ok(())
98
+ }
99
+ Ok(_) => Err(MmapError::io(
100
+ "read",
101
+ &self.path,
102
+ io::Error::from(io::ErrorKind::UnexpectedEof),
103
+ )),
104
+ Err(e) => Err(MmapError::io("read", &self.path, e)),
105
+ }
106
+ }
107
+ }
108
+
109
+ #[cfg(test)]
110
+ mod test {
111
+ use magnus::{eval, RArray, Symbol};
112
+ use rand::{thread_rng, Rng};
113
+ use sha2::{Digest, Sha256};
114
+ use std::fs;
115
+ use std::io::Write;
116
+
117
+ use super::*;
118
+ use crate::testhelper::TestFile;
119
+
120
+ #[test]
121
+ fn test_open_from_params() {
122
+ let _cleanup = unsafe { magnus::embed::init() };
123
+ let ruby = magnus::Ruby::get().unwrap();
124
+ crate::init(&ruby).unwrap();
125
+
126
+ let file_data = b"foobar";
127
+ let TestFile {
128
+ file: _file,
129
+ path,
130
+ dir: _dir,
131
+ } = TestFile::new(file_data);
132
+
133
+ let pid = "worker-1_0";
134
+ let args = RArray::from_value(
135
+ eval(&format!("['{}', :max, :gauge, '{pid}']", path.display())).unwrap(),
136
+ )
137
+ .unwrap();
138
+ let arg0 = args.shift().unwrap();
139
+ let arg1 = args.shift().unwrap();
140
+ let arg2 = args.shift().unwrap();
141
+ let arg3 = args.shift().unwrap();
142
+
143
+ let out = FileInfo::open_from_params(&[arg0, arg1, arg2, arg3]);
144
+ assert!(out.is_ok());
145
+
146
+ let out = out.unwrap();
147
+
148
+ assert_eq!(out.path, path);
149
+ assert_eq!(out.len, file_data.len());
150
+ assert_eq!(out.multiprocess_mode, Symbol::new("max"));
151
+ assert_eq!(out.type_, Symbol::new("gauge"));
152
+ assert_eq!(out.pid, pid);
153
+ }
154
+
155
+ #[test]
156
+ fn test_read_from_file() {
157
+ let _cleanup = unsafe { magnus::embed::init() };
158
+ let ruby = magnus::Ruby::get().unwrap();
159
+ crate::init(&ruby).unwrap();
160
+
161
+ const BUF_LEN: usize = 1 << 20; // 1MiB
162
+
163
+ // Create a buffer with random data.
164
+ let mut buf = vec![0u8; BUF_LEN];
165
+ thread_rng().fill(buf.as_mut_slice());
166
+
167
+ let TestFile {
168
+ file,
169
+ path,
170
+ dir: _dir,
171
+ } = TestFile::new(&buf);
172
+
173
+ let mut info = FileInfo {
174
+ file,
175
+ path: path.clone(),
176
+ len: buf.len(),
177
+ multiprocess_mode: Symbol::new("puma"),
178
+ type_: Symbol::new("max"),
179
+ pid: "worker-0_0".to_string(),
180
+ };
181
+
182
+ let mut out_buf = Vec::new();
183
+ info.read_from_file(&mut out_buf).unwrap();
184
+
185
+ assert_eq!(buf.len(), out_buf.len(), "buffer lens");
186
+
187
+ let mut in_hasher = Sha256::new();
188
+ in_hasher.update(&buf);
189
+ let in_hash = in_hasher.finalize();
190
+
191
+ let mut out_hasher = Sha256::new();
192
+ out_hasher.update(&out_buf);
193
+ let out_hash = out_hasher.finalize();
194
+
195
+ assert_eq!(in_hash, out_hash, "content hashes");
196
+ }
197
+
198
+ #[test]
199
+ fn test_read_from_file_resized() {
200
+ let _cleanup = unsafe { magnus::embed::init() };
201
+ let ruby = magnus::Ruby::get().unwrap();
202
+ crate::init(&ruby).unwrap();
203
+
204
+ const BUF_LEN: usize = 1 << 14; // 16KiB
205
+
206
+ // Create a buffer with random data.
207
+ let mut buf = vec![0u8; BUF_LEN];
208
+ thread_rng().fill(buf.as_mut_slice());
209
+
210
+ let TestFile {
211
+ file,
212
+ path,
213
+ dir: _dir,
214
+ } = TestFile::new(&buf);
215
+
216
+ let mut info = FileInfo {
217
+ file,
218
+ path: path.clone(),
219
+ len: buf.len(),
220
+ multiprocess_mode: Symbol::new("puma"),
221
+ type_: Symbol::new("max"),
222
+ pid: "worker-0_0".to_string(),
223
+ };
224
+
225
+ let mut resized_file = fs::OpenOptions::new()
226
+ .write(true)
227
+ .append(true)
228
+ .open(path)
229
+ .unwrap();
230
+
231
+ // Write data to file after it has been `stat`ed in the
232
+ // constructor.
233
+ resized_file.write_all(&[1; 1024]).unwrap();
234
+
235
+ let mut out_buf = Vec::new();
236
+ info.read_from_file(&mut out_buf).unwrap();
237
+
238
+ assert_eq!(BUF_LEN + 1024, info.len, "resized file updated len");
239
+ }
240
+ }
@@ -0,0 +1,89 @@
1
+ use magnus::exception::*;
2
+ use magnus::prelude::*;
3
+ use magnus::value::{Fixnum, Lazy, LazyId};
4
+ use magnus::{class, define_class, exception, function, method, Ruby};
5
+ use std::mem::size_of;
6
+
7
+ use crate::mmap::MmapedFile;
8
+
9
+ pub mod error;
10
+ pub mod file_entry;
11
+ pub mod file_info;
12
+ mod macros;
13
+ pub mod map;
14
+ pub mod mmap;
15
+ pub mod raw_entry;
16
+ pub mod util;
17
+ pub mod exemplars;
18
+
19
+ pub mod io {
20
+ pub mod prometheus {
21
+ pub mod client {
22
+ include!(concat!(env!("OUT_DIR"), "/io.prometheus.client.rs"));
23
+ }
24
+ }
25
+ }
26
+
27
+ #[cfg(test)]
28
+ mod testhelper;
29
+
30
+ type Result<T> = std::result::Result<T, crate::error::MmapError>;
31
+
32
+ const MAP_SHARED: i64 = libc::MAP_SHARED as i64;
33
+ const HEADER_SIZE: usize = 2 * size_of::<u32>();
34
+
35
+ static SYM_GAUGE: LazyId = LazyId::new("gauge");
36
+ static SYM_MIN: LazyId = LazyId::new("min");
37
+ static SYM_MAX: LazyId = LazyId::new("max");
38
+ static SYM_LIVESUM: LazyId = LazyId::new("livesum");
39
+ static SYM_PID: LazyId = LazyId::new("pid");
40
+ static SYM_SAMPLES: LazyId = LazyId::new("samples");
41
+
42
+ static PROM_EPARSING_ERROR: Lazy<ExceptionClass> = Lazy::new(|_| {
43
+ let prom_err = define_class(
44
+ "PrometheusParsingError",
45
+ exception::runtime_error().as_r_class(),
46
+ )
47
+ .expect("failed to create class `PrometheusParsingError`");
48
+ ExceptionClass::from_value(prom_err.as_value())
49
+ .expect("failed to create exception class from `PrometheusParsingError`")
50
+ });
51
+
52
+ #[magnus::init]
53
+ fn init(ruby: &Ruby) -> magnus::error::Result<()> {
54
+ // Initialize the static symbols
55
+ LazyId::force(&SYM_GAUGE, ruby);
56
+ LazyId::force(&SYM_MIN, ruby);
57
+ LazyId::force(&SYM_MAX, ruby);
58
+ LazyId::force(&SYM_LIVESUM, ruby);
59
+ LazyId::force(&SYM_PID, ruby);
60
+ LazyId::force(&SYM_SAMPLES, ruby);
61
+
62
+ // Initialize `PrometheusParsingError` class.
63
+ Lazy::force(&PROM_EPARSING_ERROR, ruby);
64
+
65
+ let klass = define_class("FastMmapedFileRs", class::object())?;
66
+ klass.undef_default_alloc_func();
67
+
68
+ // UNWRAP: We know `MAP_SHARED` fits in a `Fixnum`.
69
+ klass.const_set("MAP_SHARED", Fixnum::from_i64(MAP_SHARED).unwrap())?;
70
+
71
+ klass.define_singleton_method("to_metrics", function!(MmapedFile::to_metrics, 1))?;
72
+ klass.define_singleton_method("to_protobuf", function!(MmapedFile::to_protobuf, 1))?;
73
+
74
+ // Required for subclassing to work
75
+ klass.define_alloc_func::<MmapedFile>();
76
+ klass.define_singleton_method("new", method!(MmapedFile::new, -1))?;
77
+ klass.define_method("initialize", method!(MmapedFile::initialize, 1))?;
78
+ klass.define_method("slice", method!(MmapedFile::slice, -1))?;
79
+ klass.define_method("sync", method!(MmapedFile::sync, -1))?;
80
+ klass.define_method("munmap", method!(MmapedFile::munmap, 0))?;
81
+
82
+ klass.define_method("used", method!(MmapedFile::load_used, 0))?;
83
+ klass.define_method("used=", method!(MmapedFile::save_used, 1))?;
84
+ klass.define_method("fetch_entry", method!(MmapedFile::fetch_entry, 3))?;
85
+ klass.define_method("upsert_entry", method!(MmapedFile::upsert_entry, 3))?;
86
+ klass.define_method("upsert_exemplar", method!(MmapedFile::upsert_exemplar, 5))?;
87
+
88
+ Ok(())
89
+ }
@@ -0,0 +1,14 @@
1
+ #[macro_export]
2
+ macro_rules! err {
3
+ (with_errno: $err_t:expr, $($arg:expr),*) => {
4
+ {
5
+ let err = format!($($arg),*);
6
+ let strerror = strerror(errno());
7
+ Error::new($err_t, format!("{err} ({strerror})"))
8
+ }
9
+ };
10
+
11
+ ($err_t:expr, $($arg:expr),*) => {
12
+ Error::new($err_t, format!($($arg),*))
13
+ };
14
+ }