From 291dd621753cdc45fc7af7e97c4540e41e6db060 Mon Sep 17 00:00:00 2001 From: rameel Date: Tue, 22 Apr 2025 23:55:12 +0500 Subject: [PATCH] Slightly improve performance and maintainability --- .../SequentialGuidValueGenerator.cs | 35 +++++++++++++------ 1 file changed, 24 insertions(+), 11 deletions(-) diff --git a/src/EFCore/ValueGeneration/SequentialGuidValueGenerator.cs b/src/EFCore/ValueGeneration/SequentialGuidValueGenerator.cs index 569de845e67..99c87700780 100644 --- a/src/EFCore/ValueGeneration/SequentialGuidValueGenerator.cs +++ b/src/EFCore/ValueGeneration/SequentialGuidValueGenerator.cs @@ -1,6 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Buffers.Binary; using System.Runtime.InteropServices; namespace Microsoft.EntityFrameworkCore.ValueGeneration; @@ -35,17 +36,29 @@ public class SequentialGuidValueGenerator : ValueGenerator /// The value to be assigned to a property. public override Guid Next(EntityEntry entry) { - Span guidBytes = stackalloc byte[16]; - var succeeded = Guid.NewGuid().TryWriteBytes(guidBytes); - Check.DebugAssert(succeeded, "Could not write Guid to Span"); - var incrementedCounter = Interlocked.Increment(ref _counter); - Span counterBytes = stackalloc byte[sizeof(long)]; - MemoryMarshal.Write(counterBytes, in incrementedCounter); + var guid = Guid.NewGuid(); - if (!BitConverter.IsLittleEndian) - { - counterBytes.Reverse(); - } + var counter = BitConverter.IsLittleEndian + ? Interlocked.Increment(ref _counter) + : BinaryPrimitives.ReverseEndianness(Interlocked.Increment(ref _counter)); + + var counterBytes = MemoryMarshal.AsBytes( + new ReadOnlySpan(in counter)); + + // Guid uses a sequential layout where the first 8 bytes (_a, _b, _c) + // are subject to byte-swapping on big-endian systems when reading from + // or writing to a byte array (e.g., via MemoryMarshal or Guid constructors). + // The remaining 8 bytes (_d through _k) are interpreted as-is, + // regardless of endianness. + // + // Since we only modify the last 8 bytes of the Guid (bytes 8–15), + // byte order does not affect the result. + // + // This allows us to safely use MemoryMarshal.AsBytes to directly access + // and modify the Guid's underlying bytes without any extra conversions, + // which also slightly improves performance on big-endian architectures. + var guidBytes = MemoryMarshal.AsBytes( + new Span(ref guid)); guidBytes[08] = counterBytes[1]; guidBytes[09] = counterBytes[0]; @@ -56,7 +69,7 @@ public override Guid Next(EntityEntry entry) guidBytes[14] = counterBytes[3]; guidBytes[15] = counterBytes[2]; - return new Guid(guidBytes); + return guid; } ///