-
-
Save jpv001/5ac3f73dff192bb512eb to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
void Main() | |
{ | |
var d = new Dictionary<BigInteger, BigInteger>(); | |
var t = DateTime.Now; | |
var howfar = 0; | |
var r = 0; | |
for (int x = 0; x < 100000; x++) | |
{ | |
for (int i = 0; i < 10000000; i++) | |
{ | |
try | |
{ | |
d.Add(CreateFlake(t), i); | |
} | |
catch | |
{ | |
if (howfar == 0) howfar = i; | |
if (i < howfar) howfar = i; | |
i = 10000000; | |
} | |
} | |
r++; | |
d.Clear(); | |
} | |
r.Dump(); | |
howfar.Dump(); | |
} | |
// Define other methods and classes here | |
private static readonly DateTime DEFAULT_EPOCH = new DateTime(2000, 01, 01); | |
/// <summary> | |
/// The Epoch point in time from which the timestamp will be calculated. | |
/// </summary> | |
public DateTime Epoch { get; private set; } | |
/// <summary> | |
/// Creates a Flake object based on a given date and time that can be used as part of a distributed ID system. | |
/// </summary> | |
/// <returns>A Flake that wraps an underlying BigInteger value made up of 41 bits of timestamp data plus 23 bits of random bits to avoid collisions in a distributed system.</returns> | |
public virtual BigInteger CreateFlake(DateTime timestamp) | |
{ | |
if (timestamp < this.Epoch) | |
{ | |
throw new Exception("The timestamp cannot be earlier than the Epoch time being used."); | |
} | |
// 64-bit Id will be 41 bits of milliseconds + 23 bits random | |
var bigTicks = this.GetMillisecondsSinceEpoch(timestamp); | |
// Get some random bits | |
var saltBytes = this.GetRandomBytes(3); | |
// Convert the random bytes to a BigInteger so we can bit shift | |
var bigSalt = new BigInteger(saltBytes); | |
// We are going to bit-shift the two values so we end up with the | |
// correct number of bits in each value | |
bigSalt = BigInteger.Abs(bigSalt) >> 1; // Shift right to go from 24 bits to 23 | |
bigTicks = bigTicks << 23; // Shift left to make room for the Salt | |
// Bitwise OR the bits together to get one big 64-bit string where the first 41 bits | |
// are the timestamp and the last 23 are the salt | |
var result = bigTicks | bigSalt; | |
// Create a new Flake of type T that will be returned | |
return (BigInteger)result; | |
} | |
/// <summary> | |
/// Calculates the number of milliseconds that have elapsed since the Epoch time. | |
/// </summary> | |
/// <param name="now">DateTime value after Epoch time.</param> | |
/// <returns>A BigInteger value representing the number of milliseconds since the Epoch time.</returns> | |
protected virtual BigInteger GetMillisecondsSinceEpoch(DateTime now) | |
{ | |
var millisecondsSinceEpoch = (now - this.Epoch).TotalMilliseconds; | |
var bigMillisecondsSinceEpoch = new BigInteger(millisecondsSinceEpoch); | |
return bigMillisecondsSinceEpoch; | |
} | |
/// <summary> | |
/// Generates a random set of bytes. | |
/// </summary> | |
/// <param name="count">The number of bytes to randomly generate.</param> | |
/// <returns>An array of randomized bytes of the given length.</returns> | |
protected virtual byte[] GetRandomBytes(int count) | |
{ | |
var crypto = new CryptoRandom(); | |
var intValue = crypto.Next(); | |
byte[] intBytes = BitConverter.GetBytes(intValue); | |
if (BitConverter.IsLittleEndian) | |
Array.Reverse(intBytes); | |
return intBytes; | |
} | |
class CryptoRandom : RandomNumberGenerator | |
{ | |
private static RandomNumberGenerator r; | |
public CryptoRandom() | |
{ | |
r = RandomNumberGenerator.Create(); | |
} | |
public override void GetBytes(byte[] buffer) | |
{ | |
r.GetBytes(buffer); | |
} | |
public double NextDouble() | |
{ | |
var b = new byte[4]; | |
r.GetBytes(b); | |
return (double)BitConverter.ToUInt32(b, 0) / UInt32.MaxValue; | |
} | |
public int Next(int minValue, int maxValue) | |
{ | |
return (int)Math.Round(NextDouble() * (maxValue - minValue - 1)) + minValue; | |
} | |
public int Next() | |
{ | |
return Next(0, Int32.MaxValue); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment