Skip to content

Commit d2f7f2b

Browse files
authored
Merge branch 'main' into issue-2702-add-scope-attributes-test
2 parents b051d15 + 1583e70 commit d2f7f2b

File tree

2 files changed

+63
-89
lines changed

2 files changed

+63
-89
lines changed

opentelemetry/CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
- {PLACEHOLDER} - Remove the above completely. // TODO fill this when changes are actually in.
99
- Bug Fix: `InstrumentationScope` implementation for `PartialEq` and `Hash` fixed to include Attributes also.
1010
- *Breaking* Changed value type of `Baggage` from `Value` to `StringValue`
11+
- Updated `Baggage` constants to reflect latest standard (`MAX_KEY_VALUE_PAIRS` - 180 -> 64, `MAX_BYTES_FOR_ONE_PAIR` - removed) and increased insert performance see #[2284](https://github.com/open-telemetry/opentelemetry-rust/pull/2284).
1112

1213
## 0.28.0
1314

opentelemetry/src/baggage.rs

+62-89
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,14 @@
1515
//!
1616
//! [W3C Baggage]: https://w3c.github.io/baggage
1717
use crate::{Context, Key, KeyValue, StringValue};
18+
use std::collections::hash_map::Entry;
1819
use std::collections::{hash_map, HashMap};
1920
use std::fmt;
2021
use std::sync::OnceLock;
2122

2223
static DEFAULT_BAGGAGE: OnceLock<Baggage> = OnceLock::new();
2324

24-
const MAX_KEY_VALUE_PAIRS: usize = 180;
25-
const MAX_BYTES_FOR_ONE_PAIR: usize = 4096;
25+
const MAX_KEY_VALUE_PAIRS: usize = 64;
2626
const MAX_LEN_OF_ALL_PAIRS: usize = 8192;
2727

2828
/// Returns the default baggage, ensuring it is initialized only once.
@@ -49,11 +49,10 @@ fn get_default_baggage() -> &'static Baggage {
4949
///
5050
/// ### Limits
5151
///
52-
/// * Maximum number of name/value pairs: `180`.
53-
/// * Maximum number of bytes per a single name/value pair: `4096`.
52+
/// * Maximum number of name/value pairs: `64`.
5453
/// * Maximum total length of all name/value pairs: `8192`.
5554
///
56-
/// [RFC2616, Section 2.2]: https://tools.ietf.org/html/rfc2616#section-2.2
55+
/// <https://www.w3.org/TR/baggage/#limits>
5756
#[derive(Debug, Default)]
5857
pub struct Baggage {
5958
inner: HashMap<Key, (StringValue, BaggageMetadata)>,
@@ -133,6 +132,8 @@ impl Baggage {
133132
/// Same with `insert`, if the name was not present, [`None`] will be returned.
134133
/// If the name is present, the old value and metadata will be returned.
135134
///
135+
/// Also checks for [limits](https://w3c.github.io/baggage/#limits).
136+
///
136137
/// # Examples
137138
///
138139
/// ```
@@ -155,10 +156,38 @@ impl Baggage {
155156
S: Into<BaggageMetadata>,
156157
{
157158
let (key, value, metadata) = (key.into(), value.into(), metadata.into());
158-
if self.insertable(&key, &value, &metadata) {
159-
self.inner.insert(key, (value, metadata))
160-
} else {
161-
None
159+
if !key.as_str().is_ascii() {
160+
return None;
161+
}
162+
let entry_content_len =
163+
key_value_metadata_bytes_size(key.as_str(), value.as_str(), metadata.as_str());
164+
let entries_count = self.inner.len();
165+
match self.inner.entry(key) {
166+
Entry::Occupied(mut occupied_entry) => {
167+
let prev_content_len = key_value_metadata_bytes_size(
168+
occupied_entry.key().as_str(),
169+
occupied_entry.get().0.as_str(),
170+
occupied_entry.get().1.as_str(),
171+
);
172+
let new_content_len = self.kv_content_len + entry_content_len - prev_content_len;
173+
if new_content_len > MAX_LEN_OF_ALL_PAIRS {
174+
return None;
175+
}
176+
self.kv_content_len = new_content_len;
177+
Some(occupied_entry.insert((value, metadata)))
178+
}
179+
Entry::Vacant(vacant_entry) => {
180+
if entries_count == MAX_KEY_VALUE_PAIRS {
181+
return None;
182+
}
183+
let new_content_len = self.kv_content_len + entry_content_len;
184+
if new_content_len > MAX_LEN_OF_ALL_PAIRS {
185+
return None;
186+
}
187+
self.kv_content_len = new_content_len;
188+
vacant_entry.insert((value, metadata));
189+
None
190+
}
162191
}
163192
}
164193

@@ -178,59 +207,10 @@ impl Baggage {
178207
self.inner.is_empty()
179208
}
180209

181-
/// Gets an iterator over the baggage items, sorted by name.
210+
/// Gets an iterator over the baggage items, in any order.
182211
pub fn iter(&self) -> Iter<'_> {
183212
self.into_iter()
184213
}
185-
186-
/// Determine whether the key value pair exceed one of the [limits](https://w3c.github.io/baggage/#limits).
187-
/// If not, update the total length of key values
188-
fn insertable(&mut self, key: &Key, value: &StringValue, metadata: &BaggageMetadata) -> bool {
189-
if !key.as_str().is_ascii() {
190-
return false;
191-
}
192-
let value = value.as_str();
193-
if key_value_metadata_bytes_size(key.as_str(), value, metadata.as_str())
194-
< MAX_BYTES_FOR_ONE_PAIR
195-
{
196-
match self.inner.get(key) {
197-
None => {
198-
// check total length
199-
if self.kv_content_len
200-
+ metadata.as_str().len()
201-
+ value.len()
202-
+ key.as_str().len()
203-
> MAX_LEN_OF_ALL_PAIRS
204-
{
205-
return false;
206-
}
207-
// check number of pairs
208-
if self.inner.len() + 1 > MAX_KEY_VALUE_PAIRS {
209-
return false;
210-
}
211-
self.kv_content_len +=
212-
metadata.as_str().len() + value.len() + key.as_str().len()
213-
}
214-
Some((old_value, old_metadata)) => {
215-
let old_value = old_value.as_str();
216-
if self.kv_content_len - old_metadata.as_str().len() - old_value.len()
217-
+ metadata.as_str().len()
218-
+ value.len()
219-
> MAX_LEN_OF_ALL_PAIRS
220-
{
221-
return false;
222-
}
223-
self.kv_content_len =
224-
self.kv_content_len - old_metadata.as_str().len() - old_value.len()
225-
+ metadata.as_str().len()
226-
+ value.len()
227-
}
228-
}
229-
true
230-
} else {
231-
false
232-
}
233-
}
234214
}
235215

236216
/// Get the number of bytes for one key-value pair
@@ -385,13 +365,11 @@ impl BaggageExt for Context {
385365
&self,
386366
baggage: T,
387367
) -> Self {
388-
let mut merged: Baggage = self
389-
.baggage()
390-
.iter()
391-
.map(|(key, (value, metadata))| {
392-
KeyValueMetadata::new(key.clone(), value.clone(), metadata.clone())
393-
})
394-
.collect();
368+
let old = self.baggage();
369+
let mut merged = Baggage {
370+
inner: old.inner.clone(),
371+
kv_content_len: old.kv_content_len,
372+
};
395373
for kvm in baggage.into_iter().map(|kv| kv.into()) {
396374
merged.insert_with_metadata(kvm.key, kvm.value, kvm.metadata);
397375
}
@@ -531,29 +509,6 @@ mod tests {
531509
assert_eq!(baggage.len(), MAX_KEY_VALUE_PAIRS)
532510
}
533511

534-
#[test]
535-
fn insert_too_long_pair() {
536-
let pair = KeyValue::new(
537-
"test",
538-
String::from_utf8_lossy(vec![12u8; MAX_BYTES_FOR_ONE_PAIR].as_slice()).to_string(),
539-
);
540-
let mut baggage = Baggage::default();
541-
baggage.insert(pair.key.clone(), pair.value.clone());
542-
assert_eq!(
543-
baggage.len(),
544-
0,
545-
"The input pair is too long to insert into baggage"
546-
);
547-
548-
baggage.insert("test", "value");
549-
baggage.insert(pair.key.clone(), pair.value);
550-
assert_eq!(
551-
baggage.get(pair.key),
552-
Some(&StringValue::from("value")),
553-
"If the input pair is too long, then don't replace entry with same key"
554-
)
555-
}
556-
557512
#[test]
558513
fn insert_pairs_length_exceed() {
559514
let mut data = vec![];
@@ -611,4 +566,22 @@ mod tests {
611566
assert!(b.to_string().contains("bar=2;yellow"));
612567
assert!(b.to_string().contains("foo=1;red;state=on"));
613568
}
569+
570+
#[test]
571+
fn replace_existing_key() {
572+
let half_minus2: StringValue = (0..MAX_LEN_OF_ALL_PAIRS / 2 - 2)
573+
.map(|_| 'x')
574+
.collect::<String>()
575+
.into();
576+
577+
let mut b = Baggage::default();
578+
b.insert("a", half_minus2.clone()); // +1 for key
579+
b.insert("b", half_minus2); // +1 for key
580+
b.insert("c", StringValue::from(".")); // total of 2 bytes
581+
assert!(b.get("a").is_some());
582+
assert!(b.get("b").is_some());
583+
assert!(b.get("c").is_some());
584+
assert!(b.insert("c", StringValue::from("..")).is_none()); // exceeds MAX_LEN_OF_ALL_PAIRS
585+
assert_eq!(b.insert("c", StringValue::from("!")).unwrap(), ".".into()); // replaces existing
586+
}
614587
}

0 commit comments

Comments
 (0)