Skip to content

Instantly share code, notes, and snippets.

@afifmohammed
Last active August 29, 2015 14:22
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save afifmohammed/bcd74116b5d633a2ef92 to your computer and use it in GitHub Desktop.
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
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