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 +4 -4
- data/ext/fast_mmaped_file_rs/Cargo.lock +10 -2
- data/ext/fast_mmaped_file_rs/Cargo.toml +1 -1
- data/ext/fast_mmaped_file_rs/extconf.rb +2 -0
- data/ext/fast_mmaped_file_rs/src/file_entry.rs +45 -12
- data/ext/fast_mmaped_file_rs/src/map.rs +49 -15
- data/lib/prometheus/client/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f91fbb3a1899d0093d51d92ab8dceec80981c6160b3a09d35d90117f29e6c3d0
|
4
|
+
data.tar.gz: fea591800d5a3a2344082fd38df75f35aea8b5bf5394bcd7e20bf80d14dd48fd
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
-
|
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,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
|
-
|
28
|
-
|
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
|
-
|
31
|
-
|
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
|
-
|
35
|
-
|
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
|
-
|
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.
|
70
|
+
Some(file_info.pid.as_str())
|
42
71
|
} else {
|
43
72
|
None
|
44
73
|
};
|
45
74
|
|
46
|
-
Ok(
|
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
|
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
|
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
|
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(
|
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(
|
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:
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
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 =
|
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
|
-
|
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
|
-
|
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
|
-
|
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,
|
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.
|
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-
|
12
|
+
date: 2023-04-19 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rb_sys
|