Skip to content

Commit 9b42f36

Browse files
authored
Slightly improve performance and maintainability (#35981)
1 parent bad7584 commit 9b42f36

File tree

1 file changed

+24
-11
lines changed

1 file changed

+24
-11
lines changed

src/EFCore/ValueGeneration/SequentialGuidValueGenerator.cs

Lines changed: 24 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// Licensed to the .NET Foundation under one or more agreements.
22
// The .NET Foundation licenses this file to you under the MIT license.
33

4+
using System.Buffers.Binary;
45
using System.Runtime.InteropServices;
56

67
namespace Microsoft.EntityFrameworkCore.ValueGeneration;
@@ -35,17 +36,29 @@ public class SequentialGuidValueGenerator : ValueGenerator<Guid>
3536
/// <returns>The value to be assigned to a property.</returns>
3637
public override Guid Next(EntityEntry entry)
3738
{
38-
Span<byte> guidBytes = stackalloc byte[16];
39-
var succeeded = Guid.NewGuid().TryWriteBytes(guidBytes);
40-
Check.DebugAssert(succeeded, "Could not write Guid to Span");
41-
var incrementedCounter = Interlocked.Increment(ref _counter);
42-
Span<byte> counterBytes = stackalloc byte[sizeof(long)];
43-
MemoryMarshal.Write(counterBytes, in incrementedCounter);
39+
var guid = Guid.NewGuid();
4440

45-
if (!BitConverter.IsLittleEndian)
46-
{
47-
counterBytes.Reverse();
48-
}
41+
var counter = BitConverter.IsLittleEndian
42+
? Interlocked.Increment(ref _counter)
43+
: BinaryPrimitives.ReverseEndianness(Interlocked.Increment(ref _counter));
44+
45+
var counterBytes = MemoryMarshal.AsBytes(
46+
new ReadOnlySpan<long>(in counter));
47+
48+
// Guid uses a sequential layout where the first 8 bytes (_a, _b, _c)
49+
// are subject to byte-swapping on big-endian systems when reading from
50+
// or writing to a byte array (e.g., via MemoryMarshal or Guid constructors).
51+
// The remaining 8 bytes (_d through _k) are interpreted as-is,
52+
// regardless of endianness.
53+
//
54+
// Since we only modify the last 8 bytes of the Guid (bytes 8–15),
55+
// byte order does not affect the result.
56+
//
57+
// This allows us to safely use MemoryMarshal.AsBytes to directly access
58+
// and modify the Guid's underlying bytes without any extra conversions,
59+
// which also slightly improves performance on big-endian architectures.
60+
var guidBytes = MemoryMarshal.AsBytes(
61+
new Span<Guid>(ref guid));
4962

5063
guidBytes[08] = counterBytes[1];
5164
guidBytes[09] = counterBytes[0];
@@ -56,7 +69,7 @@ public override Guid Next(EntityEntry entry)
5669
guidBytes[14] = counterBytes[3];
5770
guidBytes[15] = counterBytes[2];
5871

59-
return new Guid(guidBytes);
72+
return guid;
6073
}
6174

6275
/// <summary>

0 commit comments

Comments
 (0)