Skip to content

Performance: reduce per-call SHA1 allocation for deterministic orchestration GUIDs #778

Description

1. What is the issue?

Each call to the deterministic orchestration NewGuid() implementation creates and disposes a new SHA1 HashAlgorithm instance.

2. Likely priority

Low. It affects orchestrations that use context.NewGuid() frequently, including some entity correlation paths, but other per-call allocations are likely larger.

3. Impact on performance

Repeated hash-algorithm construction adds allocation and disposal overhead during orchestration replay. The cost scales with the number of deterministic GUIDs generated per execution.

4. Details and code reference

Deterministic GUID implementation:

public override Guid NewGuid()
{
static void SwapByteArrayValues(byte[] byteArray)
{
SwapByteArrayElements(byteArray, 0, 3);
SwapByteArrayElements(byteArray, 1, 2);
SwapByteArrayElements(byteArray, 4, 5);
SwapByteArrayElements(byteArray, 6, 7);
}
static void SwapByteArrayElements(byte[] byteArray, int left, int right)
{
(byteArray[right], byteArray[left]) = (byteArray[left], byteArray[right]);
}
const string DnsNamespaceValue = "9e952958-5e33-4daf-827f-2fa12937b875";
const int DeterministicGuidVersion = 5;
Guid namespaceValueGuid = Guid.Parse(DnsNamespaceValue);
// The name is a combination of the instance ID, the current orchestrator date/time, and a counter.
string guidNameValue = string.Concat(
this.InstanceId,
"_",
this.CurrentUtcDateTime.ToString("o"),
"_",
this.newGuidCounter.ToString(CultureInfo.InvariantCulture));
this.newGuidCounter++;
byte[] nameByteArray = Encoding.UTF8.GetBytes(guidNameValue);
byte[] namespaceValueByteArray = namespaceValueGuid.ToByteArray();
SwapByteArrayValues(namespaceValueByteArray);
byte[] hashByteArray;
#pragma warning disable CA5350 // Do Not Use Weak Cryptographic Algorithms -- not for cryptography
using (HashAlgorithm hashAlgorithm = SHA1.Create()) /* CodeQL [SM02196] Suppressed: SHA1 is not used for cryptographic purposes here. The information being hashed is not sensitive,
and the goal is to generate a deterministic Guid. We cannot update to SHA2-based algorithms without breaking
customers' inflight orchestrations. */
{
hashAlgorithm.TransformBlock(namespaceValueByteArray, 0, namespaceValueByteArray.Length, null, 0);
hashAlgorithm.TransformFinalBlock(nameByteArray, 0, nameByteArray.Length);
hashByteArray = hashAlgorithm.Hash;
}
#pragma warning restore CA5350 // Do Not Use Weak Cryptographic Algorithms -- not for cryptography
byte[] newGuidByteArray = new byte[16];
Array.Copy(hashByteArray, 0, newGuidByteArray, 0, 16);
int versionValue = DeterministicGuidVersion;
newGuidByteArray[6] = (byte)((newGuidByteArray[6] & 0x0F) | (versionValue << 4));
newGuidByteArray[8] = (byte)((newGuidByteArray[8] & 0x3F) | 0x80);
SwapByteArrayValues(newGuidByteArray);
return new Guid(newGuidByteArray);

SHA1 creation is here:

byte[] hashByteArray;
#pragma warning disable CA5350 // Do Not Use Weak Cryptographic Algorithms -- not for cryptography
using (HashAlgorithm hashAlgorithm = SHA1.Create()) /* CodeQL [SM02196] Suppressed: SHA1 is not used for cryptographic purposes here. The information being hashed is not sensitive,
and the goal is to generate a deterministic Guid. We cannot update to SHA2-based algorithms without breaking
customers' inflight orchestrations. */
{
hashAlgorithm.TransformBlock(namespaceValueByteArray, 0, namespaceValueByteArray.Length, null, 0);
hashAlgorithm.TransformFinalBlock(nameByteArray, 0, nameByteArray.Length);
hashByteArray = hashAlgorithm.Hash;
}

5. Guidance for how to fix

Treat this as replay-compatibility-sensitive. Any reuse or replacement must produce byte-for-byte identical GUIDs for existing instance ID, timestamp, and counter inputs across supported target frameworks. Prefer an isolated optimization with deterministic-value regression tests before and after the change; do not change the namespace, hash input, byte ordering, SHA1 algorithm, or version-bit handling.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions