Last active
August 29, 2015 14:22
-
-
Save afifmohammed/bcd74116b5d633a2ef92 to your computer and use it in GitHub Desktop.
A test for how far we can go before SimpleFlake returns a duplicate
This file contains hidden or 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; | |
int? howfar = null; | |
var attempts = 10000000; | |
for (int x = 0; x < 1000; x++) | |
{ | |
d.Clear(); | |
for (int i = 0; i < attempts; i++) | |
{ | |
try | |
{ | |
d.Add(CreateFlake(t), i); | |
} | |
catch | |
{ | |
if(howfar == null) howfar = i; | |
if(i < howfar) howfar = i; | |
i = attempts; | |
} | |
} | |
} | |
Console.WriteLine(howfar); | |
} | |
// 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 randomBytes = new byte[count]; | |
RandomNumberGenerator.Create().GetBytes(randomBytes); | |
return randomBytes; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment