Skip to content

Commit 06196d8

Browse files
authored
fix: Use thread-safe hash for big segments hashing. (#180)
SHA256 instances are not thread-safe and under heavy-parallelism will fail. Newer .Net frameworks have a static method which is higher performance under heavy-parallelism and inherently thread-safe. This PR introduces a thin abstraction that uses the correct method in a thread-safe way depending on the framework. <!-- CURSOR_SUMMARY --> --- > [!NOTE] > Replaces a shared SHA256 instance with a thread-safe `LdSha256` utility and updates Big Segments hashing to use it. > > - **Internal hashing**: > - Add `LdSha256` utility that uses `SHA256.HashData` on .NET 5+ and per-call `ComputeHash` on older targets. > - Update `BigSegmentsInternalTypes.BigSegmentContextKeyHash` to use `LdSha256.HashData` instead of a shared `SHA256` instance. > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit d5ab7a0. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY -->
1 parent 9de8b5b commit 06196d8

File tree

2 files changed

+39
-4
lines changed

2 files changed

+39
-4
lines changed

pkgs/sdk/server/src/Internal/BigSegments/BigSegmentsInternalTypes.cs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
using System;
2-
using System.Security.Cryptography;
32
using System.Text;
43
using LaunchDarkly.Sdk.Server.Internal.Model;
54

@@ -9,11 +8,9 @@ namespace LaunchDarkly.Sdk.Server.Internal.BigSegments
98
{
109
internal static class BigSegmentsInternalTypes
1110
{
12-
private static readonly SHA256 _hasher = SHA256.Create();
13-
1411
internal static string BigSegmentContextKeyHash(string userKey) =>
1512
Convert.ToBase64String(
16-
_hasher.ComputeHash(Encoding.UTF8.GetBytes(userKey))
13+
LdSha256.HashData(Encoding.UTF8.GetBytes(userKey))
1714
);
1815

1916
internal static string MakeBigSegmentRef(Segment s) =>
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
using System.Security.Cryptography;
2+
3+
namespace LaunchDarkly.Sdk.Server.Internal
4+
{
5+
// Hasher which uses HashData on .NET 5.0+ platforms and ComputeHash on older platforms.
6+
// HashData is static and thread-safe offering better performance when available.
7+
#if NET5_0_OR_GREATER
8+
/// <summary>
9+
/// Thread-safe hasher using SHA256.HashData for .NET 5.0+ platforms.
10+
/// </summary>
11+
internal static class LdSha256
12+
{
13+
public static byte[] HashData(byte[] data) {
14+
return SHA256.HashData(data);
15+
}
16+
}
17+
#else
18+
/// <summary>
19+
/// Thread-safe hasher using SHA256.ComputeHash for .NET Framework and .netstandard targets.
20+
/// </summary>
21+
/// <remarks>
22+
/// This hasher creates a SHA256 instance per-call. This is likely to perform better under high parallelism
23+
/// than locking. With low parallelism, locking would have lower overhead and exert lower pressure on the GC.
24+
/// The pre-existing evaluation algorithm was already using per-call SHA1 instances, so this should have
25+
/// reasonable performance characteristics.
26+
/// </remarks>
27+
internal static class LdSha256
28+
{
29+
public static byte[] HashData(byte[] data)
30+
{
31+
using (var hasher = SHA256.Create())
32+
{
33+
return hasher.ComputeHash(data);
34+
}
35+
}
36+
}
37+
#endif
38+
}

0 commit comments

Comments
 (0)