55namespace Microsoft . Azure . Cosmos . Tracing
66{
77 using System ;
8- using System . Collections . Concurrent ;
98 using System . Collections . Generic ;
10- using System . Diagnostics ;
11- using System . Linq ;
12- using System . Runtime . CompilerServices ;
13- using Microsoft . Azure . Cosmos . Tracing . TraceData ;
149 using Microsoft . Azure . Documents ;
1510
1611 internal sealed class Trace : ITrace
1712 {
1813 private static readonly IReadOnlyDictionary < string , object > EmptyDictionary = new Dictionary < string , object > ( ) ;
1914 private readonly List < ITrace > children ;
20- private readonly Lazy < ConcurrentDictionary < string , object > > data ;
15+ private readonly Lazy < Dictionary < string , object > > data ;
16+ private volatile IReadOnlyDictionary < string , object > materializedData = null ;
2117 private ValueStopwatch stopwatch ;
2218
2319 private Trace (
@@ -35,7 +31,7 @@ private Trace(
3531 this . Component = component ;
3632 this . Parent = parent ;
3733 this . children = new List < ITrace > ( ) ;
38- this . data = new Lazy < ConcurrentDictionary < string , object > > ( ( ) => new ConcurrentDictionary < string , object > ( ) ) ;
34+ this . data = new Lazy < Dictionary < string , object > > ( ) ;
3935 this . Summary = summary ?? throw new ArgumentNullException ( nameof ( summary ) ) ;
4036 }
4137
@@ -57,7 +53,7 @@ private Trace(
5753
5854 public IReadOnlyList < ITrace > Children => this . children ;
5955
60- public IReadOnlyDictionary < string , object > Data => this . data . IsValueCreated ? this . data . Value : Trace . EmptyDictionary ;
56+ public IReadOnlyDictionary < string , object > Data => this . EnsureMaterializedData ( ) ;
6157
6258 public void Dispose ( )
6359 {
@@ -132,10 +128,12 @@ public static Trace GetRootTrace(
132128 /// <exception cref="ArgumentException">Thrown when the key already exists in the dictionary.</exception>
133129 public void AddDatum ( string key , TraceDatum traceDatum )
134130 {
135- if ( ! this . data . Value . TryAdd ( key , traceDatum ) )
131+ lock ( this . Name )
136132 {
137- throw new ArgumentException ( $ "An item with the same key has already been added: '{ key } '") ;
133+ this . data . Value . Add ( key , traceDatum ) ;
134+ this . materializedData = null ;
138135 }
136+
139137 this . Summary . UpdateRegionContacted ( traceDatum ) ;
140138 }
141139
@@ -148,9 +146,10 @@ public void AddDatum(string key, TraceDatum traceDatum)
148146 /// <exception cref="ArgumentException">Thrown when the key already exists in the dictionary.</exception>
149147 public void AddDatum ( string key , object value )
150148 {
151- if ( ! this . data . Value . TryAdd ( key , value ) )
149+ lock ( this . Name )
152150 {
153- throw new ArgumentException ( $ "An item with the same key has already been added: '{ key } '") ;
151+ this . data . Value . Add ( key , value ) ;
152+ this . materializedData = null ;
154153 }
155154 }
156155
@@ -162,7 +161,35 @@ public void AddDatum(string key, object value)
162161 /// <param name="value">The datum itself.</param>
163162 public void AddOrUpdateDatum ( string key , object value )
164163 {
165- this . data . Value . AddOrUpdate ( key , value , ( k , oldValue ) => value ) ;
164+ lock ( this . Name )
165+ {
166+ this . data . Value [ key ] = value ;
167+ this . materializedData = null ;
168+ }
169+ }
170+
171+ private IReadOnlyDictionary < string , object > EnsureMaterializedData ( )
172+ {
173+ IReadOnlyDictionary < string , object > snapshot = this . materializedData ;
174+ if ( snapshot != null )
175+ {
176+ return snapshot ;
177+ }
178+
179+ lock ( this . Name )
180+ {
181+ if ( snapshot != null )
182+ {
183+ return snapshot ;
184+ }
185+
186+ if ( ! this . data . IsValueCreated )
187+ {
188+ return this . materializedData = EmptyDictionary ;
189+ }
190+
191+ return this . materializedData = new Dictionary < string , object > ( this . data . Value ) ;
192+ }
166193 }
167194 }
168195}
0 commit comments