prometheus-client-mmap 0.20.1 → 0.20.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c348888918d1d6d2ff4334aa37e1ca1b27275246050db022db7723e220613717
4
- data.tar.gz: 6f082d9c9d3bb0b1181817b1ebfde447912ad8b23209e93d24350526e2118c36
3
+ metadata.gz: f91fbb3a1899d0093d51d92ab8dceec80981c6160b3a09d35d90117f29e6c3d0
4
+ data.tar.gz: fea591800d5a3a2344082fd38df75f35aea8b5bf5394bcd7e20bf80d14dd48fd
5
5
  SHA512:
6
- metadata.gz: 2824ca427aab9d85d0516c4d8f4c42bc7dfd67995a1f208dc6cd2eefcfab71716ed202de22549943b7538ff5bb87aeb94d1d9e6e1ce476bb466292f3e2679a3e
7
- data.tar.gz: 0ccb59ead46f5047cea39cddcd89d55516e30b0a09e92b25aa940b39e589b991e314264630c808b85bc3460f778ec2833d4a1111b40d82bb45fb99fe92aeb7a2
6
+ metadata.gz: f6e98dda485f79a83fe614a21c52444fad33a69b208c4a6d637516c0390f79c9c54216dda50f7b151483d3e69fe4e7739ed0076984cb7497c59110f0f941b664
7
+ data.tar.gz: 30bc5288dd7247222128b99a4cf88bdde9ca8625682b0d013dc5ea9cd6ce12aa5285be4b3a875f9a933dcc23e943c4b2cccc9ad9c53e273754a4dac46ddee1ed
@@ -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"
@@ -2,6 +2,8 @@ require "mkmf"
2
2
  require "rb_sys/mkmf"
3
3
 
4
4
  create_rust_makefile("fast_mmaped_file_rs") do |r|
5
+ r.auto_install_rust_toolchain = false
6
+
5
7
  if enable_config('fail-on-warning')
6
8
  r.extra_rustflags = ["-Dwarnings"]
7
9
  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.2'.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.2
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