prometheus-client-mmap 0.20.1 → 0.20.3

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c348888918d1d6d2ff4334aa37e1ca1b27275246050db022db7723e220613717
4
- data.tar.gz: 6f082d9c9d3bb0b1181817b1ebfde447912ad8b23209e93d24350526e2118c36
3
+ metadata.gz: a044be30f61b4d49820eb47e00c524ba90c3bb15ad8f6ddb97c0106eecda2839
4
+ data.tar.gz: aa953907ebd58fe257cb0f894e8d997746c61f38e1b45e3500e288fc5a3c54e2
5
5
  SHA512:
6
- metadata.gz: 2824ca427aab9d85d0516c4d8f4c42bc7dfd67995a1f208dc6cd2eefcfab71716ed202de22549943b7538ff5bb87aeb94d1d9e6e1ce476bb466292f3e2679a3e
7
- data.tar.gz: 0ccb59ead46f5047cea39cddcd89d55516e30b0a09e92b25aa940b39e589b991e314264630c808b85bc3460f778ec2833d4a1111b40d82bb45fb99fe92aeb7a2
6
+ metadata.gz: c499ccd0dc2442f9a5ffd0cab890a1f462a0f086bf818cb2af61c9533170fe6f0d6c5a84124053838c4be0a180ec8be29c114de45785c6066841fe88282628d0
7
+ data.tar.gz: 4bac46af2fff3c5d2332199c69ba78e625015bf5820089e295462a6d22d4f7ecab023ae138628f9e582c4738e97a4d77d939082993625a3d5a9a5ff9a448feb8
@@ -9,7 +9,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
9
9
  checksum = "2c99f64d1e06488f620f932677e24bc6e2897582980441ae90a671415bd7ec2f"
10
10
  dependencies = [
11
11
  "cfg-if",
12
- "getrandom",
13
12
  "once_cell",
14
13
  "version_check",
15
14
  ]
@@ -161,8 +160,8 @@ dependencies = [
161
160
  name = "fast_mmaped_file_rs"
162
161
  version = "0.1.0"
163
162
  dependencies = [
164
- "ahash",
165
163
  "bstr",
164
+ "hashbrown",
166
165
  "indoc",
167
166
  "libc",
168
167
  "magnus",
@@ -212,6 +211,15 @@ version = "0.3.1"
212
211
  source = "registry+https://github.com/rust-lang/crates.io-index"
213
212
  checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b"
214
213
 
214
+ [[package]]
215
+ name = "hashbrown"
216
+ version = "0.13.2"
217
+ source = "registry+https://github.com/rust-lang/crates.io-index"
218
+ checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e"
219
+ dependencies = [
220
+ "ahash",
221
+ ]
222
+
215
223
  [[package]]
216
224
  name = "hermit-abi"
217
225
  version = "0.3.1"
@@ -6,7 +6,7 @@ edition = "2021"
6
6
  # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
7
7
 
8
8
  [dependencies]
9
- ahash = "0.8"
9
+ hashbrown = "0.13"
10
10
  libc = "0.2"
11
11
  magnus = { git = "https://github.com/matsadler/magnus", branch = "main", features = ["rb-sys"] }
12
12
  memmap2 = "0.5"
@@ -1,22 +1,30 @@
1
1
  require "mkmf"
2
2
  require "rb_sys/mkmf"
3
3
 
4
- create_rust_makefile("fast_mmaped_file_rs") do |r|
5
- if enable_config('fail-on-warning')
6
- r.extra_rustflags = ["-Dwarnings"]
7
- end
4
+ if find_executable('rustc')
5
+ create_rust_makefile("fast_mmaped_file_rs") do |r|
6
+ r.auto_install_rust_toolchain = false
8
7
 
9
- if enable_config('debug')
10
- r.profile = :dev
11
- end
8
+ if enable_config('fail-on-warning')
9
+ r.extra_rustflags = ["-Dwarnings"]
10
+ end
11
+
12
+ if enable_config('debug')
13
+ r.profile = :dev
14
+ end
15
+
16
+ if enable_config('address-sanitizer')
17
+ r.extra_rustflags = ["-Zsanitizer=address"]
18
+ end
12
19
 
13
- if enable_config('address-sanitizer')
14
- r.extra_rustflags = ["-Zsanitizer=address"]
20
+ # `rb_sys/mkmf` passes all arguments after `--` directly to `cargo rustc`.
21
+ # We use this awful hack to keep compatibility with existing flags used by
22
+ # the C implementation.
23
+ trimmed_argv = ARGV.take_while { |arg| arg != "--" }
24
+ ARGV = trimmed_argv
15
25
  end
26
+ else
27
+ puts 'rustc not found, skipping Rust extension.'
16
28
 
17
- # `rb_sys/mkmf` passes all arguments after `--` directly to `cargo rustc`.
18
- # We use this awful hack to keep compatibility with existing flags used by
19
- # the C implementation.
20
- trimmed_argv = ARGV.take_while { |arg| arg != "--" }
21
- ARGV = trimmed_argv
29
+ File.write('Makefile', dummy_makefile($srcdir).join(''))
22
30
  end
@@ -1,5 +1,6 @@
1
1
  use magnus::{StaticSymbol, Symbol};
2
2
  use std::fmt::Write;
3
+ use std::str;
3
4
 
4
5
  use crate::error::{MmapError, RubyError};
5
6
  use crate::file_info::FileInfo;
@@ -23,27 +24,55 @@ pub struct EntryData {
23
24
  pub pid: Option<String>,
24
25
  }
25
26
 
26
- impl EntryData {
27
- pub fn new(raw_entry: &RawEntry, file_info: &FileInfo, pid_significant: bool) -> Result<Self> {
28
- let mut buf = Vec::new();
27
+ impl<'a> PartialEq<BorrowedData<'a>> for EntryData {
28
+ fn eq(&self, other: &BorrowedData) -> bool {
29
+ self.pid.as_deref() == other.pid && self.json == other.json
30
+ }
31
+ }
32
+
33
+ impl<'a> TryFrom<BorrowedData<'a>> for EntryData {
34
+ type Error = MmapError;
29
35
 
30
- if buf.try_reserve_exact(raw_entry.encoded_len()).is_err() {
31
- return Err(MmapError::OutOfMemory(raw_entry.encoded_len()));
36
+ fn try_from(borrowed: BorrowedData) -> Result<Self> {
37
+ let mut json = String::new();
38
+ if json.try_reserve_exact(borrowed.json.len()).is_err() {
39
+ return Err(MmapError::OutOfMemory(borrowed.json.len()));
32
40
  }
41
+ json.push_str(borrowed.json);
33
42
 
34
- buf.resize(raw_entry.encoded_len(), 0);
35
- buf.copy_from_slice(raw_entry.json());
43
+ Ok(Self {
44
+ json,
45
+ // Don't bother checking for allocation failure, typically ~10 bytes
46
+ pid: borrowed.pid.map(|p| p.to_string()),
47
+ })
48
+ }
49
+ }
50
+
51
+ /// A borrowed copy of the JSON string and pid for a `FileEntry`. We use this
52
+ /// to check if a given string/pid combination is present in the `EntryMap`,
53
+ /// copying them to owned values only when needed.
54
+ #[derive(Hash, PartialEq, Eq, PartialOrd, Ord, Clone, Debug)]
55
+ pub struct BorrowedData<'a> {
56
+ pub json: &'a str,
57
+ pub pid: Option<&'a str>,
58
+ }
36
59
 
37
- let json = String::from_utf8(buf)
60
+ impl<'a> BorrowedData<'a> {
61
+ pub fn new(
62
+ raw_entry: &'a RawEntry,
63
+ file_info: &'a FileInfo,
64
+ pid_significant: bool,
65
+ ) -> Result<Self> {
66
+ let json = str::from_utf8(raw_entry.json())
38
67
  .map_err(|e| MmapError::Encoding(format!("invalid UTF-8 in entry JSON: {e}")))?;
39
68
 
40
69
  let pid = if pid_significant {
41
- Some(file_info.pid.clone())
70
+ Some(file_info.pid.as_str())
42
71
  } else {
43
72
  None
44
73
  };
45
74
 
46
- Ok(EntryData { json, pid })
75
+ Ok(Self { json, pid })
47
76
  }
48
77
  }
49
78
 
@@ -421,7 +450,9 @@ mod test {
421
450
  .zip(file_infos)
422
451
  .map(|(entry, info)| {
423
452
  let meta = EntryMetadata::new(&entry, &info).unwrap();
424
- let data = EntryData::new(&entry, &info, meta.is_pid_significant()).unwrap();
453
+ let borrowed =
454
+ BorrowedData::new(&entry, &info, meta.is_pid_significant()).unwrap();
455
+ let data = EntryData::try_from(borrowed).unwrap();
425
456
  FileEntry { data, meta }
426
457
  })
427
458
  .collect();
@@ -528,7 +559,9 @@ mod test {
528
559
  .map(|s| RawEntry::from_slice(s).unwrap())
529
560
  .map(|entry| {
530
561
  let meta = EntryMetadata::new(&entry, &info).unwrap();
531
- let data = EntryData::new(&entry, &info, meta.is_pid_significant()).unwrap();
562
+ let borrowed =
563
+ BorrowedData::new(&entry, &info, meta.is_pid_significant()).unwrap();
564
+ let data = EntryData::try_from(borrowed).unwrap();
532
565
  FileEntry { data, meta }
533
566
  })
534
567
  .collect();
@@ -1,9 +1,11 @@
1
- use ahash::AHashMap;
1
+ use hashbrown::hash_map::RawEntryMut;
2
+ use hashbrown::HashMap;
2
3
  use magnus::{exception::*, Error, RArray};
4
+ use std::hash::{BuildHasher, Hash, Hasher};
3
5
  use std::mem::size_of;
4
6
 
5
7
  use crate::error::MmapError;
6
- use crate::file_entry::{EntryData, EntryMetadata, FileEntry};
8
+ use crate::file_entry::{BorrowedData, EntryData, EntryMetadata, FileEntry};
7
9
  use crate::file_info::FileInfo;
8
10
  use crate::raw_entry::RawEntry;
9
11
  use crate::util::read_u32;
@@ -17,12 +19,12 @@ use crate::{err, HEADER_SIZE};
17
19
  /// allows us to have multiple entries on the map for multiple pids using the
18
20
  /// same string.
19
21
  #[derive(Default, Debug)]
20
- pub struct EntryMap(AHashMap<EntryData, EntryMetadata>);
22
+ pub struct EntryMap(HashMap<EntryData, EntryMetadata>);
21
23
 
22
24
  impl EntryMap {
23
25
  /// Construct a new EntryMap.
24
26
  pub fn new() -> Self {
25
- Self(AHashMap::new())
27
+ Self(HashMap::new())
26
28
  }
27
29
 
28
30
  /// Given a list of files, read each one into memory and parse the metrics it contains.
@@ -95,12 +97,28 @@ impl EntryMap {
95
97
  /// Check if the `EntryMap` already contains the JSON string.
96
98
  /// If yes, update the associated value, if not insert the
97
99
  /// entry into the map.
98
- pub fn merge_or_store(&mut self, data: EntryData, meta: EntryMetadata) {
99
- if let Some(existing) = self.0.get_mut(&data) {
100
- existing.merge(&meta);
101
- } else {
102
- self.0.insert(data, meta);
100
+ pub fn merge_or_store(&mut self, data: BorrowedData, meta: EntryMetadata) -> Result<()> {
101
+ // Manually hash the `BorrowedData` and perform an equality check on the
102
+ // key. This allows us to perform the comparison without allocating a
103
+ // new `EntryData` that may not be needed.
104
+ let mut state = self.0.hasher().build_hasher();
105
+ data.hash(&mut state);
106
+ let hash = state.finish();
107
+
108
+ match self.0.raw_entry_mut().from_hash(hash, |k| k == &data) {
109
+ RawEntryMut::Vacant(entry) => {
110
+ // Allocate a new `EntryData` as the JSON/pid combination is
111
+ // not present in the map.
112
+ let owned = EntryData::try_from(data)?;
113
+ entry.insert(owned, meta);
114
+ }
115
+ RawEntryMut::Occupied(mut entry) => {
116
+ let existing = entry.get_mut();
117
+ existing.merge(&meta);
118
+ }
103
119
  }
120
+
121
+ Ok(())
104
122
  }
105
123
 
106
124
  /// Parse metrics data from a `.db` file and store in the `EntryMap`.
@@ -135,9 +153,9 @@ impl EntryMap {
135
153
  }
136
154
 
137
155
  let meta = EntryMetadata::new(&raw_entry, &file_info)?;
138
- let data = EntryData::new(&raw_entry, &file_info, meta.is_pid_significant())?;
156
+ let data = BorrowedData::new(&raw_entry, &file_info, meta.is_pid_significant())?;
139
157
 
140
- self.merge_or_store(data, meta);
158
+ self.merge_or_store(data, meta)?;
141
159
 
142
160
  pos += raw_entry.total_len();
143
161
  }
@@ -155,6 +173,16 @@ mod test {
155
173
  use crate::file_entry::FileEntry;
156
174
  use crate::testhelper::{self, TestFile};
157
175
 
176
+ impl EntryData {
177
+ /// A helper function for tests to convert owned data to references.
178
+ fn as_borrowed(&self) -> BorrowedData {
179
+ BorrowedData {
180
+ json: &self.json,
181
+ pid: self.pid.as_deref(),
182
+ }
183
+ }
184
+ }
185
+
158
186
  #[test]
159
187
  fn test_into_sorted() {
160
188
  let _cleanup = unsafe { magnus::embed::init() };
@@ -311,7 +339,9 @@ mod test {
311
339
  map.0
312
340
  .insert(starting_entry.data.clone(), starting_entry.meta.clone());
313
341
 
314
- map.merge_or_store(matching_entry.data, matching_entry.meta);
342
+ let matching_borrowed = matching_entry.data.as_borrowed();
343
+ map.merge_or_store(matching_borrowed, matching_entry.meta)
344
+ .unwrap();
315
345
 
316
346
  assert_eq!(
317
347
  5.0,
@@ -320,10 +350,12 @@ mod test {
320
350
  );
321
351
  assert_eq!(1, map.0.len(), "no entry added");
322
352
 
353
+ let same_key_different_worker_borrowed = same_key_different_worker.data.as_borrowed();
323
354
  map.merge_or_store(
324
- same_key_different_worker.data,
355
+ same_key_different_worker_borrowed,
325
356
  same_key_different_worker.meta,
326
- );
357
+ )
358
+ .unwrap();
327
359
 
328
360
  assert_eq!(
329
361
  5.0,
@@ -333,7 +365,9 @@ mod test {
333
365
 
334
366
  assert_eq!(2, map.0.len(), "additional entry added");
335
367
 
336
- map.merge_or_store(unmatched_entry.data, unmatched_entry.meta);
368
+ let unmatched_entry_borrowed = unmatched_entry.data.as_borrowed();
369
+ map.merge_or_store(unmatched_entry_borrowed, unmatched_entry.meta)
370
+ .unwrap();
337
371
 
338
372
  assert_eq!(
339
373
  5.0,
@@ -1,5 +1,5 @@
1
1
  module Prometheus
2
2
  module Client
3
- VERSION = '0.20.1'.freeze
3
+ VERSION = '0.20.3'.freeze
4
4
  end
5
5
  end
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.20.1
4
+ version: 0.20.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tobias Schmidt
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2023-04-15 00:00:00.000000000 Z
12
+ date: 2023-04-19 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rb_sys