i'm currently trying to rewrite sql server newSequentialId() function in pure c# that is performing as fast as possible and eats minimum memory.
Question is can I it be done better - current benchamark shows it is at most 2x slower than native function used by SqlServer (p/invoke)?
using System;
using System.Buffers;
using System.Linq;
using System.Net.NetworkInformation;
using System.Threading;
namespace PerfBenchmarkDotNet
{
internal static class FastGuid
{
private static readonly byte[] macBytes;
private static long baseDateTicks;
private static long ClockSequenceNumber = 0;
static FastGuid()
{
macBytes = GetDefaultMacAdress();
baseDateTicks = new DateTime(1582, 10, 15, 0, 0, 0, DateTimeKind.Utc).Ticks;
}
public static Guid NewGuid()
{
var guidArray = ArrayPool<byte>.Shared.Rent(16);
var nowTicks = DateTime.UtcNow.Ticks;
var sequenceNumber = Interlocked.Increment(ref ClockSequenceNumber) % 65536;
var ticksDiff = nowTicks - baseDateTicks;
var ticksDiffBytes = BitConverter.GetBytes(ticksDiff);
// Copy the bytes into the guid
// mac
guidArray[15] = macBytes[5];
guidArray[14] = macBytes[4];
guidArray[13] = macBytes[3];
guidArray[12] = macBytes[2];
guidArray[11] = macBytes[1];
guidArray[10] = macBytes[0];
// sequence number
guidArray[8] = (byte)(sequenceNumber >> 8);
guidArray[9] = (byte)(sequenceNumber);
// time
guidArray[7] = ticksDiffBytes[0];
guidArray[6] = ticksDiffBytes[1];
guidArray[5] = ticksDiffBytes[2];
guidArray[4] = ticksDiffBytes[3];
guidArray[3] = ticksDiffBytes[4];
guidArray[2] = ticksDiffBytes[5];
guidArray[1] = ticksDiffBytes[6];
guidArray[0] = ticksDiffBytes[7];
var guid = new Guid(guidArray);
ArrayPool<byte>.Shared.Return(guidArray);
return guid;
}
private static byte[] GetDefaultMacAdress()
{
var nic = NetworkInterface.GetAllNetworkInterfaces().FirstOrDefault();
if (nic != null)
{
return nic.GetPhysicalAddress().GetAddressBytes();
}
var fallback = Guid.NewGuid().ToByteArray();
return fallback.Take(6).ToArray();
}
}
}