@@ -7,12 +7,12 @@ mod sum;
7
7
8
8
use core:: fmt;
9
9
use std:: collections:: { HashMap , HashSet } ;
10
- use std:: mem:: take ;
10
+ use std:: mem:: swap ;
11
11
use std:: ops:: { Add , AddAssign , DerefMut , Sub } ;
12
12
use std:: sync:: atomic:: { AtomicBool , AtomicI64 , AtomicU64 , AtomicUsize , Ordering } ;
13
13
use std:: sync:: { Arc , RwLock } ;
14
14
15
- use aggregate:: is_under_cardinality_limit;
15
+ use aggregate:: { is_under_cardinality_limit, STREAM_CARDINALITY_LIMIT } ;
16
16
pub ( crate ) use aggregate:: { AggregateBuilder , ComputeAggregation , Measure } ;
17
17
pub ( crate ) use exponential_histogram:: { EXPO_MAX_SCALE , EXPO_MIN_SCALE } ;
18
18
use once_cell:: sync:: Lazy ;
51
51
{
52
52
/// Trackers store the values associated with different attribute sets.
53
53
trackers : RwLock < HashMap < Vec < KeyValue > , Arc < A > > > ,
54
+
55
+ /// Used by collect exclusively. The data type must match the one used in
56
+ /// `trackers` to allow mem::swap.
57
+ trackers_for_collect : RwLock < HashMap < Vec < KeyValue > , Arc < A > > > ,
58
+
54
59
/// Number of different attribute set stored in the `trackers` map.
55
60
count : AtomicUsize ,
56
61
/// Indicates whether a value with no attributes has been stored.
67
72
{
68
73
fn new ( config : A :: InitConfig ) -> Self {
69
74
ValueMap {
70
- trackers : RwLock :: new ( HashMap :: new ( ) ) ,
75
+ trackers : RwLock :: new ( HashMap :: with_capacity ( 1 + STREAM_CARDINALITY_LIMIT ) ) ,
76
+ // TODO: For cumulative, this is not required, so avoid this
77
+ // pre-allocation.
78
+ trackers_for_collect : RwLock :: new ( HashMap :: with_capacity ( 1 + STREAM_CARDINALITY_LIMIT ) ) ,
71
79
has_no_attribute_value : AtomicBool :: new ( false ) ,
72
80
no_attribute_tracker : A :: create ( & config) ,
73
81
count : AtomicUsize :: new ( 0 ) ,
@@ -170,19 +178,23 @@ where
170
178
) ) ;
171
179
}
172
180
173
- let trackers = match self . trackers . write ( ) {
174
- Ok ( mut trackers) => {
181
+ if let Ok ( mut trackers_collect) = self . trackers_for_collect . write ( ) {
182
+ if let Ok ( mut trackers_current) = self . trackers . write ( ) {
183
+ swap ( trackers_collect. deref_mut ( ) , trackers_current. deref_mut ( ) ) ;
175
184
self . count . store ( 0 , Ordering :: SeqCst ) ;
176
- take ( trackers. deref_mut ( ) )
185
+ } else {
186
+ otel_warn ! ( name: "MeterProvider.InternalError" , message = "Metric collection failed. Report this issue in OpenTelemetry repo." , details ="ValueMap trackers lock poisoned" ) ;
187
+ return ;
177
188
}
178
- Err ( _) => todo ! ( ) ,
179
- } ;
180
189
181
- let mut seen = HashSet :: new ( ) ;
182
- for ( attrs, tracker) in trackers. into_iter ( ) {
183
- if seen. insert ( Arc :: as_ptr ( & tracker) ) {
184
- dest. push ( map_fn ( attrs, tracker. clone_and_reset ( & self . config ) ) ) ;
190
+ let mut seen = HashSet :: new ( ) ;
191
+ for ( attrs, tracker) in trackers_collect. drain ( ) {
192
+ if seen. insert ( Arc :: as_ptr ( & tracker) ) {
193
+ dest. push ( map_fn ( attrs, tracker. clone_and_reset ( & self . config ) ) ) ;
194
+ }
185
195
}
196
+ } else {
197
+ otel_warn ! ( name: "MeterProvider.InternalError" , message = "Metric collection failed. Report this issue in OpenTelemetry repo." , details ="ValueMap trackers for collect lock poisoned" ) ;
186
198
}
187
199
}
188
200
}
0 commit comments