Additional documentation and bounding checks
This commit is contained in:
@@ -9,8 +9,9 @@ import java.util.Objects;
|
|||||||
import static java.lang.System.currentTimeMillis;
|
import static java.lang.System.currentTimeMillis;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generates the SnowflakeIDs. Must be initialized with a machine ID between 0 and 1023.
|
* 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.
|
* 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
|
* @author Alix von Schirp
|
||||||
* @since 1.0.0
|
* @since 1.0.0
|
||||||
@@ -37,7 +38,11 @@ public class SnowflakeIDGenerator {
|
|||||||
* Default is 12.
|
* Default is 12.
|
||||||
*/
|
*/
|
||||||
private final long SEQUENCE_BITS;
|
private final long SEQUENCE_BITS;
|
||||||
|
/**
|
||||||
|
* Amount of bits reserved for timestamp.
|
||||||
|
* Default is 41.
|
||||||
|
*/
|
||||||
|
private final long TIMESTAMP_BITS;
|
||||||
/**
|
/**
|
||||||
* The calculated maximum machine ID.
|
* The calculated maximum machine ID.
|
||||||
* Defaults to 1023.
|
* Defaults to 1023.
|
||||||
@@ -48,7 +53,11 @@ public class SnowflakeIDGenerator {
|
|||||||
* Defaults to 4095.
|
* Defaults to 4095.
|
||||||
*/
|
*/
|
||||||
private final long MAX_SEQUENCE;
|
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>)
|
* 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;
|
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 // expected to be null if not initialized by orchestrator, loaded from config
|
||||||
* @param machineId The machineID used for generation
|
* @param epoch The snowflake epoch used for generation // expected to be null if not initialized by orchestrator, loaded from config
|
||||||
* @param epoch The snowflake epoch used for generation
|
* @param machineIdBits The amount of bits used for the machineID // expected to be null if not initialized by orchestrator, loaded from config
|
||||||
* @param machineIdBits The amount of bits used for the machineID
|
* @param sequenceBits The amount of bits used for sequence counter // expected to be null if not initialized by orchestrator, loaded from config
|
||||||
* @param sequenceBits The amount of bits used for sequence counter
|
* @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
|
//init constants
|
||||||
MACHINE_ID_BITS = Objects.requireNonNullElse(machineIdBits,
|
MACHINE_ID_BITS = Objects.requireNonNullElse(machineIdBits,
|
||||||
Long.parseLong(Configuration.getInstance().get(ConfigurationValues.MACHINE_ID_BITS)));
|
Long.parseLong(Configuration.getInstance().get(ConfigurationValues.MACHINE_ID_BITS)));
|
||||||
@@ -92,23 +100,63 @@ public class SnowflakeIDGenerator {
|
|||||||
Long.parseLong(Configuration.getInstance().get(ConfigurationValues.SEQUENCE_BITS)));
|
Long.parseLong(Configuration.getInstance().get(ConfigurationValues.SEQUENCE_BITS)));
|
||||||
MAX_SEQUENCE = (1L << SEQUENCE_BITS) - 1;
|
MAX_SEQUENCE = (1L << SEQUENCE_BITS) - 1;
|
||||||
|
|
||||||
|
TIMESTAMP_BITS = 63L - MACHINE_ID_BITS - SEQUENCE_BITS;
|
||||||
|
MAX_TIMESTAMP = (1L << TIMESTAMP_BITS) -1;
|
||||||
|
|
||||||
EPOCH = Objects.requireNonNullElse(epoch,
|
EPOCH = Objects.requireNonNullElse(epoch,
|
||||||
Long.parseLong(Configuration.getInstance().get(ConfigurationValues.EPOCH)));
|
Long.parseLong(Configuration.getInstance().get(ConfigurationValues.EPOCH)));
|
||||||
|
|
||||||
MACHINE_ID_SHIFT = SEQUENCE_BITS;
|
MACHINE_ID_SHIFT = SEQUENCE_BITS;
|
||||||
TIMESTAMP_SHIFT = SEQUENCE_BITS + MACHINE_ID_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()){
|
if(EPOCH > currentTimeMillis()){
|
||||||
throw new IllegalArgumentException("Epoch may not be in the future.");
|
throw new IllegalArgumentException("Epoch may not be in the future.");
|
||||||
}
|
}
|
||||||
|
if(EPOCH+MAX_TIMESTAMP <= currentTimeMillis()){
|
||||||
if (machineId < 0 || machineId > MAX_MACHINE_ID) {
|
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);
|
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() {
|
public synchronized long generateID() {
|
||||||
long currentTimestamp = currentTimeMillis();
|
long currentTimestamp = currentTimeMillis();
|
||||||
|
|
||||||
@@ -150,8 +198,8 @@ public class SnowflakeIDGenerator {
|
|||||||
INSTANCE = new SnowflakeIDGenerator(machineId, epoch, machineIdBits, sequenceBits);
|
INSTANCE = new SnowflakeIDGenerator(machineId, epoch, machineIdBits, sequenceBits);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void init(long machineId){
|
public static void init(){
|
||||||
INSTANCE = new SnowflakeIDGenerator(machineId, null, null, null);
|
INSTANCE = new SnowflakeIDGenerator(null, null, null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static SnowflakeIDGenerator getInstance() {
|
public static SnowflakeIDGenerator getInstance() {
|
||||||
@@ -190,6 +238,14 @@ public class SnowflakeIDGenerator {
|
|||||||
public long getMachineId() {
|
public long getMachineId() {
|
||||||
return machineId;
|
return machineId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public long getTIMESTAMP_BITS() {
|
||||||
|
return TIMESTAMP_BITS;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getMAX_TIMESTAMP() {
|
||||||
|
return MAX_TIMESTAMP;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user