Skip to content

Commit

Permalink
Fix #2248 duplicate key errors on dropped span stats update
Browse files Browse the repository at this point in the history
  • Loading branch information
Mpdreamz committed Feb 7, 2024
1 parent 3f57699 commit c5a1c32
Showing 1 changed file with 22 additions and 27 deletions.
49 changes: 22 additions & 27 deletions src/Elastic.Apm/Model/Transaction.cs
Original file line number Diff line number Diff line change
Expand Up @@ -357,7 +357,7 @@ private void CheckAndCaptureBaggage()
/// <summary>
/// Internal dictionary to keep track of and look up dropped span stats.
/// </summary>
private Dictionary<DroppedSpanStatsKey, DroppedSpanStats> _droppedSpanStatsMap;
private ConcurrentDictionary<DroppedSpanStatsKey, DroppedSpanStats> _droppedSpanStatsMap;

private bool _isEnded;

Expand Down Expand Up @@ -552,38 +552,33 @@ private Activity StartActivity(bool shouldRestartTrace)
return activity;
}

private readonly object _lock = new();
internal void UpdateDroppedSpanStats(string serviceTargetType, string serviceTargetName, string destinationServiceResource, Outcome outcome,
double duration
)
{
//lock the lazy initialization of the dictionary
if (_droppedSpanStatsMap == null)
{
_droppedSpanStatsMap = new Dictionary<DroppedSpanStatsKey, DroppedSpanStats>
{
{
new DroppedSpanStatsKey(serviceTargetType, serviceTargetName, outcome),
new DroppedSpanStats(serviceTargetType, serviceTargetName, destinationServiceResource, outcome, duration)
}
};
}
else
{
if (_droppedSpanStatsMap.Count >= 128)
return;
lock (_lock) _droppedSpanStatsMap ??= new ConcurrentDictionary<DroppedSpanStatsKey, DroppedSpanStats>();

if (_droppedSpanStatsMap.TryGetValue(new DroppedSpanStatsKey(serviceTargetType, serviceTargetName, outcome), out var item))
{
item.Duration ??=
new DroppedSpanStats.DroppedSpanDuration { Sum = new DroppedSpanStats.DroppedSpanDuration.DroppedSpanDurationSum() };

item.Duration.Count++;
item.Duration.Sum.UsRaw += duration;
}
else
{
_droppedSpanStatsMap.Add(new DroppedSpanStatsKey(serviceTargetType, serviceTargetName, outcome),
new DroppedSpanStats(serviceTargetType, serviceTargetName, destinationServiceResource, outcome, duration));
}
lock (_lock)
{
//AddOrUpdate callbacks can run multiple times so still wrapping this in a lock
var key = new DroppedSpanStatsKey(serviceTargetType, serviceTargetName, outcome);
_droppedSpanStatsMap.AddOrUpdate(key,
key => new DroppedSpanStats(serviceTargetType, serviceTargetName, destinationServiceResource, outcome, duration),
(_, value) =>
{
lock (_lock)
{
value.Duration ??=
new DroppedSpanStats.DroppedSpanDuration { Sum = new DroppedSpanStats.DroppedSpanDuration.DroppedSpanDurationSum() };

value.Duration.Count++;
value.Duration.Sum.UsRaw += duration;
return value;
}
});
}
}

Expand Down

0 comments on commit c5a1c32

Please sign in to comment.