Skip to content

Commit 306e429

Browse files
committed
Skip Dictionary allocation when all LogEvents in single bucket
1 parent 46bf237 commit 306e429

File tree

4 files changed

+49
-14
lines changed

4 files changed

+49
-14
lines changed

src/NLog.Extensions.AzureDataTables/DataTablesTarget.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,8 @@ struct TablePartitionKey : IEquatable<TablePartitionKey>
3535

3636
public TablePartitionKey(string tableName, string partitionKey)
3737
{
38-
TableName = tableName;
39-
PartitionKey = partitionKey;
38+
TableName = tableName ?? string.Empty;
39+
PartitionKey = partitionKey ?? string.Empty;
4040
}
4141

4242
public bool Equals(TablePartitionKey other)

src/NLog.Extensions.AzureEventHub/EventHubTarget.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -362,7 +362,7 @@ protected override Task WriteAsyncTask(IList<LogEventInfo> logEvents, Cancellati
362362
}
363363
}
364364

365-
var partitionBuckets = PartitionKey != null ? SortHelpers.BucketSort(logEvents, _getEventHubPartitionKeyDelegate) : new Dictionary<string, IList<LogEventInfo>>() { { string.Empty, logEvents } };
365+
var partitionBuckets = PartitionKey != null ? SortHelpers.BucketSort(logEvents, _getEventHubPartitionKeyDelegate) : new[] { new KeyValuePair<string, IList<LogEventInfo>>(string.Empty, logEvents) };
366366
IList<Task> multipleTasks = partitionBuckets.Count > 1 ? new List<Task>(partitionBuckets.Count) : null;
367367
foreach (var partitionBucket in partitionBuckets)
368368
{

src/NLog.Extensions.AzureServiceBus/ServiceBusTarget.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -425,7 +425,7 @@ protected override Task WriteAsyncTask(IList<LogEventInfo> logEvents, Cancellati
425425
}
426426
}
427427

428-
var partitionBuckets = (SessionId != null || PartitionKey != null) ? SortHelpers.BucketSort(logEvents, _getMessagePartitionKeyDelegate) : new Dictionary<string, IList<LogEventInfo>>() { { string.Empty, logEvents } };
428+
var partitionBuckets = (SessionId != null || PartitionKey != null) ? SortHelpers.BucketSort(logEvents, _getMessagePartitionKeyDelegate) : new [] { new KeyValuePair<string, IList<LogEventInfo>>(string.Empty, logEvents) };
429429
IList<Task> multipleTasks = partitionBuckets.Count > 1 ? new List<Task>(partitionBuckets.Count) : null;
430430
foreach (var partitionBucket in partitionBuckets)
431431
{

src/NLog.Extensions.AzureStorage/SortHelpers.cs

Lines changed: 45 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -22,24 +22,59 @@ internal static class SortHelpers
2222
/// <param name="inputs">The inputs.</param>
2323
/// <param name="keySelector">The key selector.</param>
2424
/// <returns></returns>
25-
internal static Dictionary<TKey, IList<TValue>> BucketSort<TValue, TKey>(IList<TValue> inputs, KeySelector<TValue, TKey> keySelector) where TKey : IEquatable<TKey>
25+
internal static ICollection<KeyValuePair<TKey, IList<TValue>>> BucketSort<TValue, TKey>(IList<TValue> inputs, KeySelector<TValue, TKey> keySelector) where TKey : IEquatable<TKey>
2626
{
27-
var retVal = new Dictionary<TKey, IList<TValue>>();
27+
if (inputs.Count == 0)
28+
return Array.Empty<KeyValuePair<TKey, IList<TValue>>>();
2829

29-
for (int i = 0; i < inputs.Count; ++i)
30+
Dictionary<TKey, IList<TValue>> buckets = null;
31+
TKey firstBucketKey = keySelector(inputs[0]);
32+
for (int i = 1; i < inputs.Count; ++i)
3033
{
31-
var input = inputs[i];
32-
var keyValue = keySelector(input);
33-
if (!retVal.TryGetValue(keyValue, out var eventsInBucket))
34+
TKey keyValue = keySelector(inputs[i]);
35+
if (buckets is null)
3436
{
35-
eventsInBucket = new List<TValue>(inputs.Count - i);
36-
retVal.Add(keyValue, eventsInBucket);
37+
if (!firstBucketKey.Equals(keyValue))
38+
{
39+
// Multiple buckets needed, allocate full dictionary
40+
buckets = CreateBucketDictionaryWithValue(inputs, i, firstBucketKey, keyValue);
41+
}
3742
}
43+
else
44+
{
45+
if (!buckets.TryGetValue(keyValue, out var eventsInBucket))
46+
{
47+
eventsInBucket = new List<TValue>();
48+
buckets.Add(keyValue, eventsInBucket);
49+
}
50+
eventsInBucket.Add(inputs[i]);
51+
}
52+
}
3853

39-
eventsInBucket.Add(input);
54+
if (buckets is null)
55+
{
56+
// All inputs belong to the same bucket
57+
return new[] { new KeyValuePair<TKey, IList<TValue>>(firstBucketKey, inputs) };
58+
}
59+
else
60+
{
61+
return buckets;
62+
}
63+
}
64+
65+
private static Dictionary<TKey, IList<TValue>> CreateBucketDictionaryWithValue<TValue, TKey>(IList<TValue> inputs, int currentIndex, TKey firstBucketKey, TKey nextBucketKey)
66+
{
67+
var buckets = new Dictionary<TKey, IList<TValue>>();
68+
var firstBucket = new List<TValue>(currentIndex);
69+
for (int i = 0; i < currentIndex; i++)
70+
{
71+
firstBucket.Add(inputs[i]);
4072
}
73+
buckets[firstBucketKey] = firstBucket;
4174

42-
return retVal;
75+
var nextBucket = new List<TValue> { inputs[currentIndex] };
76+
buckets[nextBucketKey] = nextBucket;
77+
return buckets;
4378
}
4479
}
4580
}

0 commit comments

Comments
 (0)