11mod aggregate;
22mod exponential_histogram;
3+ mod hashed;
34mod histogram;
45mod last_value;
56mod precomputed_sum;
@@ -16,13 +17,14 @@ use std::sync::{Arc, Mutex, RwLock};
1617use aggregate:: is_under_cardinality_limit;
1718pub ( crate ) use aggregate:: { AggregateBuilder , ComputeAggregation , Measure } ;
1819pub ( crate ) use exponential_histogram:: { EXPO_MAX_SCALE , EXPO_MIN_SCALE } ;
20+ use hashed:: { Hashed , HashedNoOpBuilder } ;
1921use once_cell:: sync:: Lazy ;
2022use opentelemetry:: { otel_warn, KeyValue } ;
2123
22- use crate :: metrics :: AttributeSet ;
24+ use super :: sort_and_dedup ;
2325
24- pub ( crate ) static STREAM_OVERFLOW_ATTRIBUTES : Lazy < Vec < KeyValue > > =
25- Lazy :: new ( || vec ! [ KeyValue :: new( "otel.metric.overflow" , "true" ) ] ) ;
26+ pub ( crate ) static STREAM_OVERFLOW_ATTRIBUTES : Lazy < Hashed < ' static , [ KeyValue ] > > =
27+ Lazy :: new ( || Hashed :: from_owned ( vec ! [ KeyValue :: new( "otel.metric.overflow" , "true" ) ] ) ) ;
2628
2729pub ( crate ) trait Aggregator {
2830 /// A static configuration that is needed in order to initialize aggregator.
@@ -60,10 +62,10 @@ where
6062 // for performance reasons, no_attribs tracker
6163 no_attribs : NoAttribs < A > ,
6264 // for performance reasons, to handle attributes in the provided order
63- all_attribs : RwLock < HashMap < Vec < KeyValue > , Arc < A > > > ,
65+ all_attribs : RwLock < HashMap < Hashed < ' static , [ KeyValue ] > , Arc < A > , HashedNoOpBuilder > > ,
6466 // different order of attribute keys should still map to same tracker instance
6567 // this helps to achieve that and also enables implementing collection efficiently
66- sorted_attribs : Mutex < HashMap < Vec < KeyValue > , Arc < A > > > ,
68+ sorted_attribs : Mutex < HashMap < Hashed < ' static , [ KeyValue ] > , Arc < A > , HashedNoOpBuilder > > ,
6769 /// Configuration for an Aggregator
6870 config : A :: InitConfig ,
6971}
7880 tracker : A :: create ( & config) ,
7981 is_set : AtomicBool :: new ( false ) ,
8082 } ,
81- all_attribs : RwLock :: new ( HashMap :: new ( ) ) ,
82- sorted_attribs : Mutex :: new ( HashMap :: new ( ) ) ,
83+ all_attribs : RwLock :: new ( HashMap :: default ( ) ) ,
84+ sorted_attribs : Mutex :: new ( HashMap :: default ( ) ) ,
8385 config,
8486 }
8587 }
@@ -91,10 +93,12 @@ where
9193 return ;
9294 }
9395
96+ let attributes = Hashed :: from_borrowed ( attributes) ;
97+
9498 // Try to retrieve and update the tracker with the attributes in the provided order first
9599 match self . all_attribs . read ( ) {
96100 Ok ( trackers) => {
97- if let Some ( tracker) = trackers. get ( attributes) {
101+ if let Some ( tracker) = trackers. get ( & attributes) {
98102 tracker. update ( value) ;
99103 return ;
100104 }
@@ -103,7 +107,7 @@ where
103107 } ;
104108
105109 // Get or create a tracker
106- let sorted_attrs = AttributeSet :: from ( attributes) . into_vec ( ) ;
110+ let sorted_attrs = Hashed :: from_owned ( sort_and_dedup ( & attributes) ) ;
107111 let Ok ( mut sorted_trackers) = self . sorted_attribs . lock ( ) else {
108112 return ;
109113 } ;
@@ -135,7 +139,7 @@ where
135139 let Ok ( mut all_trackers) = self . all_attribs . write ( ) else {
136140 return ;
137141 } ;
138- all_trackers. insert ( attributes. to_vec ( ) , new_tracker) ;
142+ all_trackers. insert ( attributes. into_owned ( ) , new_tracker) ;
139143 }
140144
141145 /// Iterate through all attribute sets and populate `DataPoints` in readonly mode.
@@ -160,7 +164,7 @@ where
160164 }
161165
162166 for ( attrs, tracker) in trackers. into_iter ( ) {
163- dest. push ( map_fn ( attrs, & tracker) ) ;
167+ dest. push ( map_fn ( attrs. clone ( ) . into_inner_owned ( ) , & tracker) ) ;
164168 }
165169 }
166170
@@ -173,7 +177,7 @@ where
173177 // reset sorted trackers so new attributes set will be written into new hashmap
174178 let trackers = match self . sorted_attribs . lock ( ) {
175179 Ok ( mut trackers) => {
176- let new = HashMap :: with_capacity ( trackers. len ( ) ) ;
180+ let new = HashMap :: with_capacity_and_hasher ( trackers. len ( ) , HashedNoOpBuilder :: default ( ) ) ;
177181 replace ( trackers. deref_mut ( ) , new)
178182 }
179183 Err ( _) => return ,
@@ -195,7 +199,7 @@ where
195199
196200 for ( attrs, tracker) in trackers. into_iter ( ) {
197201 let tracker = Arc :: into_inner ( tracker) . expect ( "the only instance" ) ;
198- dest. push ( map_fn ( attrs, tracker) ) ;
202+ dest. push ( map_fn ( attrs. into_inner_owned ( ) , tracker) ) ;
199203 }
200204 }
201205}
@@ -403,6 +407,7 @@ impl AtomicallyUpdate<f64> for f64 {
403407
404408#[ cfg( test) ]
405409mod tests {
410+
406411 use super :: * ;
407412
408413 #[ test]
0 commit comments