|
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); |
1. What is the issue?
Each call to the deterministic orchestration
NewGuid()implementation creates and disposes a new SHA1HashAlgorithminstance.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:
durabletask-dotnet/src/Worker/Core/Shims/TaskOrchestrationContextWrapper.cs
Lines 403 to 458 in 883211a
SHA1 creation is here:
durabletask-dotnet/src/Worker/Core/Shims/TaskOrchestrationContextWrapper.cs
Lines 437 to 446 in 883211a
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.