Additional documentation and bounding checks
This commit is contained in:
@@ -9,8 +9,9 @@ import java.util.Objects;
|
||||
import static java.lang.System.currentTimeMillis;
|
||||
|
||||
/**
|
||||
* Generates the SnowflakeIDs. Must be initialized with a machine ID between 0 and 1023.
|
||||
* Can generate up to 4096 IDs per millisecond. If this limit is hit, generation will be halted until the next millisecond.
|
||||
* Generates the SnowflakeIDs. Must be initialized with a machine ID between 0 and 1023.<br>
|
||||
* Can generate up to 4096 IDs per millisecond. If this limit is hit, generation will be halted until the next millisecond.<br>
|
||||
* Snowflakes always have a max size of 63 bits and can therefore be saved as a {@code long} (64-bit integer).
|
||||
*
|
||||
* @author Alix von Schirp
|
||||
* @since 1.0.0
|
||||
@@ -37,7 +38,11 @@ public class SnowflakeIDGenerator {
|
||||
* Default is 12.
|
||||
*/
|
||||
private final long SEQUENCE_BITS;
|
||||
|
||||
/**
|
||||
* Amount of bits reserved for timestamp.
|
||||
* Default is 41.
|
||||
*/
|
||||
private final long TIMESTAMP_BITS;
|
||||
/**
|
||||
* The calculated maximum machine ID.
|
||||
* Defaults to 1023.
|
||||
@@ -48,7 +53,11 @@ public class SnowflakeIDGenerator {
|
||||
* Defaults to 4095.
|
||||
*/
|
||||
private final long MAX_SEQUENCE;
|
||||
|
||||
/**
|
||||
* The calculated maximum timestamp.
|
||||
* Defaults to 2199023255551, which gives roughly 69 years.
|
||||
*/
|
||||
private final long MAX_TIMESTAMP;
|
||||
/**
|
||||
* How far to shift the machine ID (timestamp + machine + <b><i>sequence</i></b>)
|
||||
*/
|
||||
@@ -72,17 +81,16 @@ public class SnowflakeIDGenerator {
|
||||
*/
|
||||
private long lastTimestamp = -1L;
|
||||
|
||||
// Constructor
|
||||
|
||||
/**
|
||||
* Used for initiating constants and state and performing bound checks on {@code EPOCH}, {@code MAX_TIMESTAMP} and {@code machineId}.
|
||||
*
|
||||
*
|
||||
* @param machineId The machineID used for generation
|
||||
* @param epoch The snowflake epoch used for generation
|
||||
* @param machineIdBits The amount of bits used for the machineID
|
||||
* @param sequenceBits The amount of bits used for sequence counter
|
||||
* @param machineId The machineID used for generation // expected to be null if not initialized by orchestrator, loaded from config
|
||||
* @param epoch The snowflake epoch used for generation // expected to be null if not initialized by orchestrator, loaded from config
|
||||
* @param machineIdBits The amount of bits used for the machineID // expected to be null if not initialized by orchestrator, loaded from config
|
||||
* @param sequenceBits The amount of bits used for sequence counter // expected to be null if not initialized by orchestrator, loaded from config
|
||||
* @throws IllegalArgumentException if any bound checks fail.
|
||||
*/
|
||||
private SnowflakeIDGenerator(long machineId, @Nullable Long epoch, @Nullable Long machineIdBits, @Nullable Long sequenceBits) {
|
||||
private SnowflakeIDGenerator(@Nullable Long machineId, @Nullable Long epoch, @Nullable Long machineIdBits, @Nullable Long sequenceBits) throws IllegalArgumentException{
|
||||
//init constants
|
||||
MACHINE_ID_BITS = Objects.requireNonNullElse(machineIdBits,
|
||||
Long.parseLong(Configuration.getInstance().get(ConfigurationValues.MACHINE_ID_BITS)));
|
||||
@@ -92,23 +100,63 @@ public class SnowflakeIDGenerator {
|
||||
Long.parseLong(Configuration.getInstance().get(ConfigurationValues.SEQUENCE_BITS)));
|
||||
MAX_SEQUENCE = (1L << SEQUENCE_BITS) - 1;
|
||||
|
||||
TIMESTAMP_BITS = 63L - MACHINE_ID_BITS - SEQUENCE_BITS;
|
||||
MAX_TIMESTAMP = (1L << TIMESTAMP_BITS) -1;
|
||||
|
||||
EPOCH = Objects.requireNonNullElse(epoch,
|
||||
Long.parseLong(Configuration.getInstance().get(ConfigurationValues.EPOCH)));
|
||||
|
||||
MACHINE_ID_SHIFT = SEQUENCE_BITS;
|
||||
TIMESTAMP_SHIFT = SEQUENCE_BITS + MACHINE_ID_BITS;
|
||||
|
||||
//init state
|
||||
this.machineId = Objects.requireNonNullElse(machineId,
|
||||
Long.parseLong(Configuration.getInstance().get(ConfigurationValues.MACHINE_ID)));
|
||||
|
||||
//Bound checks
|
||||
if(EPOCH > currentTimeMillis()){
|
||||
throw new IllegalArgumentException("Epoch may not be in the future.");
|
||||
}
|
||||
|
||||
if (machineId < 0 || machineId > MAX_MACHINE_ID) {
|
||||
if(EPOCH+MAX_TIMESTAMP <= currentTimeMillis()){
|
||||
throw new IllegalArgumentException("Latest possible timestamp may not be in the past.");
|
||||
}
|
||||
if (this.machineId < 0 || this.machineId > MAX_MACHINE_ID) {
|
||||
throw new IllegalArgumentException("Machine ID must be between 0 and " + MAX_MACHINE_ID);
|
||||
}
|
||||
this.machineId = machineId;
|
||||
}
|
||||
|
||||
// Method to generate a new ID
|
||||
/**
|
||||
* Generates a new snowflake ID.<br>
|
||||
* It uses a long (64-bit signed int) made up of (in default configuration):
|
||||
* <table>
|
||||
* <tr>
|
||||
* <th>bit(s)</th>
|
||||
* <th>content</th>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>0</td>
|
||||
* <td>0 (signed positive)</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>1-41</td>
|
||||
* <td>timestamp (<code>current unix time</code> - <code>epoch</code>)</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>42-51</td>
|
||||
* <td>machineID</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>52-63</td>
|
||||
* <td>sequence</td>
|
||||
* </tr>
|
||||
* </table>
|
||||
* Generation will be halted
|
||||
* <ul>
|
||||
* <li>if the clock moves backwards (e.g. fast clock after ntp synchronization) until {@code last generated milli}<{@code current milli}</li>
|
||||
* <li>if {@code count(generated IDs this millisecond)} is greater than {@code MAX_SEQUENCE} until next millisecond</li>
|
||||
* </ul>
|
||||
* @return the generated ID
|
||||
*/
|
||||
public synchronized long generateID() {
|
||||
long currentTimestamp = currentTimeMillis();
|
||||
|
||||
@@ -150,8 +198,8 @@ public class SnowflakeIDGenerator {
|
||||
INSTANCE = new SnowflakeIDGenerator(machineId, epoch, machineIdBits, sequenceBits);
|
||||
}
|
||||
|
||||
public static void init(long machineId){
|
||||
INSTANCE = new SnowflakeIDGenerator(machineId, null, null, null);
|
||||
public static void init(){
|
||||
INSTANCE = new SnowflakeIDGenerator(null, null, null, null);
|
||||
}
|
||||
|
||||
public static SnowflakeIDGenerator getInstance() {
|
||||
@@ -190,6 +238,14 @@ public class SnowflakeIDGenerator {
|
||||
public long getMachineId() {
|
||||
return machineId;
|
||||
}
|
||||
|
||||
public long getTIMESTAMP_BITS() {
|
||||
return TIMESTAMP_BITS;
|
||||
}
|
||||
|
||||
public long getMAX_TIMESTAMP() {
|
||||
return MAX_TIMESTAMP;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user