Skip to content

Instantly share code, notes, and snippets.

@bflorat
Last active December 4, 2020 20:58
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save bflorat/d7d152059b65844531b3c69e4438d00e to your computer and use it in GitHub Desktop.
Save bflorat/d7d152059b65844531b3c69e4438d00e to your computer and use it in GitHub Desktop.
sequential UUID using current time.Based on https://blog.2ndquadrant.com/sequential-uuid-generators/
package uuid;
import java.nio.ByteBuffer;
import java.security.SecureRandom;
import java.time.Instant;
import java.util.UUID;
public class OtherUUIDUtil {
private static final int UUID_LENGTH = 16;
private static final int DEFAULT_INTERVAL_LENGTH = 60;
private static final int DEFAULT_INTERAVL_COUNT = 65536;
private static volatile SecureRandom numberGenerator = null;
/**
* Static factory to generate sequential UUID using current time
* <p>
* The timestamp-based sequential UUID generator define the group size and group
* count based on data extracted from current timestamp.
* <p>
* The interval_length (60 seconds by default) is defined as number of seconds
* where UUIDs share the same prefix). The prefix length is determined by the
* number of intervals (65536 by default, i.e. 2B). With these parameters the
* generator wraps around every ~45 days.
*
* @return A sequentialy generated {@code UUID} using current time
*/
public static UUID timeUUID() {
return timeUUID(DEFAULT_INTERVAL_LENGTH, DEFAULT_INTERAVL_COUNT);
}
/**
* Static factory to generate sequential UUID using current time
* <p>
* The timestamp-based sequential UUID generator define the group size and group
* count based on data extracted from current timestamp.
*
* @param intervalLength
* The number of seconds where {@code UUID} share the same prefix
* @param intervalCount
* Used to derive the prefix length
* @return A sequentialy generated {@code UUID} using current time
*/
public static UUID timeUUID(int intervalLength, int intervalCount) {
assert intervalLength > 1 : "length of interval must be a positive integer";
assert intervalCount > 1 : "number of intervals must be a positive integer";
SecureRandom ng = numberGenerator;
if (ng == null)
numberGenerator = ng = new SecureRandom();
int i;
ByteBuffer buffer = ByteBuffer.allocate(UUID_LENGTH);
long epoch = Instant.now().getEpochSecond();
byte[] val = longToTwoLeastSignificantBytes(epoch / intervalLength);
int prefixBytes = 0;
while (intervalCount > 1) {
intervalCount /= 256;
prefixBytes++;
}
for (i = 0; i < prefixBytes; i++)
buffer.put(i, val[prefixBytes - 1 - i]);
byte[] randomBytes = new byte[UUID_LENGTH - prefixBytes];
ng.nextBytes(randomBytes);
for (i = 0; i < randomBytes.length; i++)
buffer.put(i + prefixBytes, randomBytes[i]);
return new UUID(buffer.getLong(), buffer.getLong());
}
public static byte[] longToTwoLeastSignificantBytes(long l) {
byte[] result = new byte[2];
result[0] = (byte) (l & 0xFF);
result[1] = (byte) ((l >> 8) & 0xFF);
return result;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment