diff --git a/cosid-core/src/main/java/me/ahoo/cosid/accessor/AbstractIdMetadata.java b/cosid-core/src/main/java/me/ahoo/cosid/accessor/AbstractIdMetadata.java index c4b731b0cf..f085843085 100644 --- a/cosid-core/src/main/java/me/ahoo/cosid/accessor/AbstractIdMetadata.java +++ b/cosid-core/src/main/java/me/ahoo/cosid/accessor/AbstractIdMetadata.java @@ -18,7 +18,10 @@ /** - * Abstract {@link IdMetadata}. + * Abstract base implementation of {@link IdMetadata}. + * + *
Provides common functionality for ID metadata implementations, + * including lazy generator initialization. * * @author ahoo wang */ @@ -27,6 +30,11 @@ public abstract class AbstractIdMetadata implements IdMetadata { private final IdDefinition idDefinition; private final LazyIdGenerator idGenerator; + /** + * Creates an instance with the given ID definition. + * + * @param idDefinition the ID definition + */ public AbstractIdMetadata(IdDefinition idDefinition) { this.idDefinition = idDefinition; this.idGenerator = new LazyIdGenerator(idDefinition.getGeneratorName()); diff --git a/cosid-core/src/main/java/me/ahoo/cosid/accessor/CosIdGetter.java b/cosid-core/src/main/java/me/ahoo/cosid/accessor/CosIdGetter.java index 43418b8770..adca19ce3a 100644 --- a/cosid-core/src/main/java/me/ahoo/cosid/accessor/CosIdGetter.java +++ b/cosid-core/src/main/java/me/ahoo/cosid/accessor/CosIdGetter.java @@ -14,12 +14,20 @@ package me.ahoo.cosid.accessor; /** - * CosId Getter. + * Interface for getting the ID value from an object. + * + *
Used by frameworks (MyBatis, etc.) to extract the ID from entities. * * @author ahoo wang */ public interface CosIdGetter { + /** + * Gets the ID value from the target object. + * + * @param target the object to get ID from + * @return the ID value + */ Object getId(Object target); } diff --git a/cosid-core/src/main/java/me/ahoo/cosid/accessor/CosIdSetter.java b/cosid-core/src/main/java/me/ahoo/cosid/accessor/CosIdSetter.java index 4bda2759b7..cf30286dd4 100644 --- a/cosid-core/src/main/java/me/ahoo/cosid/accessor/CosIdSetter.java +++ b/cosid-core/src/main/java/me/ahoo/cosid/accessor/CosIdSetter.java @@ -14,12 +14,20 @@ package me.ahoo.cosid.accessor; /** - * CosId Setter. + * Interface for setting the ID value on an object. + * + *
Used by frameworks (MyBatis, etc.) to set the ID on entities. * * @author ahoo wang */ public interface CosIdSetter { + /** + * Sets the ID value on the target object. + * + * @param target the object to set ID on + * @param id the ID value to set + */ void setId(Object target, Object id); } diff --git a/cosid-core/src/main/java/me/ahoo/cosid/accessor/DefaultCosIdAccessor.java b/cosid-core/src/main/java/me/ahoo/cosid/accessor/DefaultCosIdAccessor.java index a2f5294b56..ae46cfdf59 100644 --- a/cosid-core/src/main/java/me/ahoo/cosid/accessor/DefaultCosIdAccessor.java +++ b/cosid-core/src/main/java/me/ahoo/cosid/accessor/DefaultCosIdAccessor.java @@ -21,6 +21,9 @@ /** * Default {@link CosIdAccessor} implementation. * + *
Provides ID get/set operations on entities and ensures IDs are generated + * when missing. Supports Long, Integer, and String ID types. + * * @author ahoo wang */ public class DefaultCosIdAccessor extends AbstractIdMetadata implements CosIdAccessor { @@ -29,6 +32,13 @@ public class DefaultCosIdAccessor extends AbstractIdMetadata implements CosIdAcc private final CosIdSetter setter; private final EnsureId ensureId; + /** + * Creates a new accessor. + * + * @param idDefinition the ID definition + * @param getter the getter for extracting ID from entities + * @param setter the setter for setting ID on entities + */ public DefaultCosIdAccessor(IdDefinition idDefinition, CosIdGetter getter, CosIdSetter setter) { super(idDefinition); this.getter = getter; @@ -57,10 +67,20 @@ public void setId(Object target, Object id) { setter.setId(target, id); } + /** + * Gets the getter. + * + * @return the getter + */ public CosIdGetter getGetter() { return getter; } + /** + * Gets the setter. + * + * @return the setter + */ public CosIdSetter getSetter() { return setter; } @@ -71,6 +91,9 @@ public boolean ensureId(Object target) { return ensureId.ensureId(target); } + /** + * Ensures ID is generated for String ID types. + */ public class EnsureStringId implements EnsureId { @Override @@ -85,6 +108,9 @@ public boolean ensureId(Object target) { } } + /** + * Ensures ID is generated for Long ID types. + */ public class EnsureLongId implements EnsureId { private static final long MIN_ID = 0; @@ -99,6 +125,9 @@ public boolean ensureId(Object target) { } } + /** + * Ensures ID is generated for Integer ID types. + */ public class EnsureIntegerId implements EnsureId { private static final int MIN_ID = 0; private final IntegerIdGenerator integerIdGenerator; diff --git a/cosid-core/src/main/java/me/ahoo/cosid/accessor/IdMetadata.java b/cosid-core/src/main/java/me/ahoo/cosid/accessor/IdMetadata.java index 8a5819c8f0..1dc450c2ae 100644 --- a/cosid-core/src/main/java/me/ahoo/cosid/accessor/IdMetadata.java +++ b/cosid-core/src/main/java/me/ahoo/cosid/accessor/IdMetadata.java @@ -20,29 +20,62 @@ import java.lang.reflect.Field; /** - * Id Metadata. + * Metadata container for ID field information. + * + *
Provides access to ID definition, generator, and field metadata + * for objects annotated with {@code @CosId}. * * @author ahoo wang */ @Immutable public interface IdMetadata { + /** + * Gets the ID definition. + * + * @return the ID definition + */ IdDefinition getIdDefinition(); + /** + * Gets the generator name from the ID definition. + * + * @return the generator name + */ default String getGeneratorName() { return getIdDefinition().getGeneratorName(); } + /** + * Gets the ID generator. + * + * @return the ID generator + */ IdGenerator getIdGenerator(); + /** + * Gets the ID field from the definition. + * + * @return the ID field + */ default Field getIdField() { return getIdDefinition().getIdField(); } + /** + * Gets the declaring class of the ID field. + * + * @return the declaring class + */ default Class> getIdDeclaringClass() { return getIdField().getDeclaringClass(); } + /** + * Gets the type of the ID field. + * + * @return the ID type + */ default Class> getIdType() { return getIdDefinition().getIdType(); } diff --git a/cosid-core/src/main/java/me/ahoo/cosid/accessor/IdTypeNotSupportException.java b/cosid-core/src/main/java/me/ahoo/cosid/accessor/IdTypeNotSupportException.java index bbf4b8c34b..44a7031bca 100644 --- a/cosid-core/src/main/java/me/ahoo/cosid/accessor/IdTypeNotSupportException.java +++ b/cosid-core/src/main/java/me/ahoo/cosid/accessor/IdTypeNotSupportException.java @@ -20,7 +20,9 @@ import java.lang.reflect.Field; /** - * ID Type Not Support Exception. + * Exception thrown when an ID field type is not supported. + * + *
CosId only supports Long, Integer, and String ID types. * * @author ahoo wang */ @@ -28,11 +30,21 @@ public class IdTypeNotSupportException extends CosIdException { private final Field idField; + /** + * Creates a new exception. + * + * @param idField the unsupported ID field + */ public IdTypeNotSupportException(Field idField) { super(Strings.lenientFormat("ID type only supports Long/long/Integer/int/String, idField:[%s]!", idField)); this.idField = idField; } + /** + * Gets the unsupported ID field. + * + * @return the field + */ public Field getIdField() { return idField; } diff --git a/cosid-core/src/main/java/me/ahoo/cosid/accessor/MultipleIdNotSupportException.java b/cosid-core/src/main/java/me/ahoo/cosid/accessor/MultipleIdNotSupportException.java index 18d8204153..2f0793019c 100644 --- a/cosid-core/src/main/java/me/ahoo/cosid/accessor/MultipleIdNotSupportException.java +++ b/cosid-core/src/main/java/me/ahoo/cosid/accessor/MultipleIdNotSupportException.java @@ -18,7 +18,9 @@ import com.google.common.base.Strings; /** - * Multiple Id Not Support Exception. + * Exception thrown when an entity has multiple @CosId fields. + * + *
CosId only supports a single ID field per entity. * * @author ahoo wang */ @@ -26,11 +28,21 @@ public class MultipleIdNotSupportException extends CosIdException { private final Class> declaringClass; + /** + * Creates a new exception. + * + * @param declaringClass the class with multiple ID fields + */ public MultipleIdNotSupportException(Class> declaringClass) { super(Strings.lenientFormat("Not support defining multiple CosIds, declaringClass:[%s]!", declaringClass)); this.declaringClass = declaringClass; } + /** + * Gets the declaring class. + * + * @return the class + */ public Class> getDeclaringClass() { return declaringClass; } diff --git a/cosid-core/src/main/java/me/ahoo/cosid/accessor/field/FieldGetter.java b/cosid-core/src/main/java/me/ahoo/cosid/accessor/field/FieldGetter.java index 5046db0211..8dc58e6b45 100644 --- a/cosid-core/src/main/java/me/ahoo/cosid/accessor/field/FieldGetter.java +++ b/cosid-core/src/main/java/me/ahoo/cosid/accessor/field/FieldGetter.java @@ -20,13 +20,18 @@ import java.lang.reflect.Field; /** - * Field Getter. + * ID getter that accesses field directly. * * @author ahoo wang */ public class FieldGetter implements CosIdGetter { private final Field idField; + /** + * Creates a getter for the specified field. + * + * @param idField the field to access + */ public FieldGetter(Field idField) { CosIdAccessor.ensureAccessible(idField); this.idField = idField; diff --git a/cosid-core/src/main/java/me/ahoo/cosid/accessor/field/FieldSetter.java b/cosid-core/src/main/java/me/ahoo/cosid/accessor/field/FieldSetter.java index 071d365028..26e03167b7 100644 --- a/cosid-core/src/main/java/me/ahoo/cosid/accessor/field/FieldSetter.java +++ b/cosid-core/src/main/java/me/ahoo/cosid/accessor/field/FieldSetter.java @@ -20,13 +20,18 @@ import java.lang.reflect.Field; /** - * Field Setter. + * ID setter that accesses field directly. * * @author ahoo wang */ public class FieldSetter implements CosIdSetter { private final Field idField; + /** + * Creates a setter for the specified field. + * + * @param idField the field to access + */ public FieldSetter(Field idField) { CosIdAccessor.ensureAccessible(idField); this.idField = idField; diff --git a/cosid-core/src/main/java/me/ahoo/cosid/accessor/method/MethodGetter.java b/cosid-core/src/main/java/me/ahoo/cosid/accessor/method/MethodGetter.java index bcd7468449..133602f472 100644 --- a/cosid-core/src/main/java/me/ahoo/cosid/accessor/method/MethodGetter.java +++ b/cosid-core/src/main/java/me/ahoo/cosid/accessor/method/MethodGetter.java @@ -21,18 +21,28 @@ import java.lang.reflect.Method; /** - * Method Getter. + * ID getter that accesses via getter method. * * @author ahoo wang */ public class MethodGetter implements CosIdGetter { private final Method getter; + /** + * Creates a getter for the specified method. + * + * @param getter the getter method + */ public MethodGetter(Method getter) { CosIdAccessor.ensureAccessible(getter); this.getter = getter; } + /** + * Gets the getter method. + * + * @return the getter method + */ public Method getGetter() { return getter; } diff --git a/cosid-core/src/main/java/me/ahoo/cosid/accessor/method/MethodSetter.java b/cosid-core/src/main/java/me/ahoo/cosid/accessor/method/MethodSetter.java index 7c4c0c0fca..62b7ca270b 100644 --- a/cosid-core/src/main/java/me/ahoo/cosid/accessor/method/MethodSetter.java +++ b/cosid-core/src/main/java/me/ahoo/cosid/accessor/method/MethodSetter.java @@ -21,18 +21,28 @@ import java.lang.reflect.Method; /** - * Method Setter. + * ID setter that accesses via setter method. * * @author ahoo wang */ public class MethodSetter implements CosIdSetter { private final Method setter; + /** + * Creates a setter for the specified method. + * + * @param setter the setter method + */ public MethodSetter(Method setter) { CosIdAccessor.ensureAccessible(setter); this.setter = setter; } + /** + * Gets the setter method. + * + * @return the setter method + */ public Method getSetter() { return setter; } diff --git a/cosid-core/src/main/java/me/ahoo/cosid/accessor/parser/CompositeFieldDefinitionParser.java b/cosid-core/src/main/java/me/ahoo/cosid/accessor/parser/CompositeFieldDefinitionParser.java index 9e617c8217..e109579c92 100644 --- a/cosid-core/src/main/java/me/ahoo/cosid/accessor/parser/CompositeFieldDefinitionParser.java +++ b/cosid-core/src/main/java/me/ahoo/cosid/accessor/parser/CompositeFieldDefinitionParser.java @@ -19,18 +19,25 @@ import java.util.List; /** - * Composite {@link FieldDefinitionParser}. + * Composite parser that tries multiple parsers in sequence. + * + *
Tries each parser in order until one returns a non-NOT_FOUND result.
*
* @see FieldDefinitionParser
* @see NamedDefinitionParser
*/
public class CompositeFieldDefinitionParser implements FieldDefinitionParser {
private final List Parses classes to find @CosId annotated fields
+ * and creates accessors using getters/setters or direct field access.
*
* @author ahoo wang
*/
@@ -54,6 +57,11 @@ public class DefaultAccessorParser implements CosIdAccessorParser {
private final ConcurrentHashMap Creates an ID definition for fields matching the specified name.
*
* @author ahoo wang
*/
@@ -27,6 +29,11 @@ public class NamedDefinitionParser implements FieldDefinitionParser {
private final String idFieldName;
+ /**
+ * Creates a parser for the specified field name.
+ *
+ * @param idFieldName the field name to match
+ */
public NamedDefinitionParser(String idFieldName) {
this.idFieldName = idFieldName;
}
diff --git a/cosid-core/src/main/java/me/ahoo/cosid/accessor/registry/CosIdAccessorRegistry.java b/cosid-core/src/main/java/me/ahoo/cosid/accessor/registry/CosIdAccessorRegistry.java
index 82a2ba413f..81d5581ada 100644
--- a/cosid-core/src/main/java/me/ahoo/cosid/accessor/registry/CosIdAccessorRegistry.java
+++ b/cosid-core/src/main/java/me/ahoo/cosid/accessor/registry/CosIdAccessorRegistry.java
@@ -18,19 +18,45 @@
import com.google.errorprone.annotations.ThreadSafe;
/**
- * CosIdAccessor Registry.
+ * Registry for managing {@link CosIdAccessor} instances.
+ *
+ * Provides registration and lookup of ID accessors for classes,
+ * enabling automatic ID injection for entities.
*
* @author ahoo wang
*/
@ThreadSafe
public interface CosIdAccessorRegistry {
+ /**
+ * Registers a class, parsing its accessor from annotations.
+ *
+ * @param clazz the class to register
+ */
void register(Class> clazz);
+ /**
+ * Registers a class with a specific accessor.
+ *
+ * @param clazz the class to register
+ * @param cosIdAccessor the accessor to use
+ */
void register(Class> clazz, CosIdAccessor cosIdAccessor);
+ /**
+ * Gets the accessor for a class.
+ *
+ * @param clazz the class
+ * @return the accessor
+ */
CosIdAccessor get(Class> clazz);
+ /**
+ * Ensures the target object has an ID, registering if needed.
+ *
+ * @param target the target object
+ * @return true if ID was ensured
+ */
default boolean ensureId(Object target) {
CosIdAccessor cosIdAccessor = get(target.getClass());
if (CosIdAccessor.NOT_FOUND.equals(cosIdAccessor)) {
diff --git a/cosid-core/src/main/java/me/ahoo/cosid/accessor/registry/DefaultAccessorRegistry.java b/cosid-core/src/main/java/me/ahoo/cosid/accessor/registry/DefaultAccessorRegistry.java
index 4261b51ef1..ab60db3184 100644
--- a/cosid-core/src/main/java/me/ahoo/cosid/accessor/registry/DefaultAccessorRegistry.java
+++ b/cosid-core/src/main/java/me/ahoo/cosid/accessor/registry/DefaultAccessorRegistry.java
@@ -19,7 +19,10 @@
import java.util.concurrent.ConcurrentHashMap;
/**
- * Default CosIdAccessorRegistry implementation.
+ * Default implementation of {@link CosIdAccessorRegistry}.
+ *
+ * Uses a concurrent hash map for thread-safe registration
+ * and lazy parsing of accessors.
*
* @author ahoo wang
*/
@@ -28,6 +31,11 @@ public class DefaultAccessorRegistry implements CosIdAccessorRegistry {
private final ConcurrentHashMap Scans classpath for classes with @CosId annotations
+ * and registers them with the accessor registry.
*
* @author ahoo wang
*/
@@ -39,10 +42,24 @@ public class DefaultCosIdScanner implements CosIdScanner {
private final CosIdAccessorParser cosIdAccessorParser;
private final CosIdAccessorRegistry cosIdAccessorRegistry;
+ /**
+ * Creates a scanner with field definition parser.
+ *
+ * @param basePackages packages to scan
+ * @param fieldDefinitionParser the field parser
+ * @param cosIdAccessorRegistry the registry
+ */
public DefaultCosIdScanner(String[] basePackages, FieldDefinitionParser fieldDefinitionParser, CosIdAccessorRegistry cosIdAccessorRegistry) {
this(basePackages, new DefaultAccessorParser(fieldDefinitionParser), cosIdAccessorRegistry);
}
+ /**
+ * Creates a scanner with accessor parser.
+ *
+ * @param basePackages packages to scan
+ * @param cosIdAccessorParser the accessor parser
+ * @param cosIdAccessorRegistry the registry
+ */
public DefaultCosIdScanner(String[] basePackages, CosIdAccessorParser cosIdAccessorParser, CosIdAccessorRegistry cosIdAccessorRegistry) {
this.basePackages = basePackages;
this.cosIdAccessorRegistry = cosIdAccessorRegistry;
diff --git a/cosid-core/src/main/java/me/ahoo/cosid/annotation/AnnotationDefinitionParser.java b/cosid-core/src/main/java/me/ahoo/cosid/annotation/AnnotationDefinitionParser.java
index b3f0c9316a..d9f7f3b733 100644
--- a/cosid-core/src/main/java/me/ahoo/cosid/annotation/AnnotationDefinitionParser.java
+++ b/cosid-core/src/main/java/me/ahoo/cosid/annotation/AnnotationDefinitionParser.java
@@ -23,7 +23,10 @@
import java.util.Optional;
/**
- * Annotation FieldDefinitionParser.
+ * Parses {@link CosId} annotations to create {@link IdDefinition}.
+ *
+ * Checks for field-level @CosId annotation first,
+ * then looks for type-level annotation with matching field name.
*
* @author ahoo wang
* @see CosId
@@ -31,6 +34,9 @@
@Slf4j
public class AnnotationDefinitionParser implements FieldDefinitionParser {
+ /**
+ * Shared singleton instance.
+ */
public static final AnnotationDefinitionParser INSTANCE = new AnnotationDefinitionParser();
@Override
diff --git a/cosid-core/src/main/java/me/ahoo/cosid/annotation/CosId.java b/cosid-core/src/main/java/me/ahoo/cosid/annotation/CosId.java
index d5e75eae0c..977ff4bcea 100644
--- a/cosid-core/src/main/java/me/ahoo/cosid/annotation/CosId.java
+++ b/cosid-core/src/main/java/me/ahoo/cosid/annotation/CosId.java
@@ -22,7 +22,13 @@
import java.lang.annotation.Target;
/**
- * Define CosId.
+ * Annotation to mark fields or classes for CosId.
+ *
+ * Can be applied to:
+ * This converter wraps another IdConverter and adds a date-based prefix,
+ * useful for time-based partitioning or bucketing of IDs.
+ *
+ * @author ahoo wang
+ */
public class DatePrefixIdConverter implements IdConverter, Decorator The group key is obtained from the current GroupedAccessor context.
+ *
+ * @author ahoo wang
+ */
public class GroupedPrefixIdConverter implements IdConverter, Decorator Encodes long IDs as strings using 36 characters (10 digits + 26 uppercase letters).
+ * Maximum 13 characters needed for full long range.
*
* @author ahoo wang
*/
public final class Radix36IdConverter extends RadixIdConverter {
+ /**
+ * Maximum character size (13 for full long range).
+ */
public static final int MAX_CHAR_SIZE = 13;
+ /**
+ * Radix value (36).
+ */
public static final int RADIX = 36;
+ /**
+ * Shared instance without padding.
+ */
public static final Radix36IdConverter INSTANCE = new Radix36IdConverter(false, MAX_CHAR_SIZE);
+ /**
+ * Shared instance with padding.
+ */
public static final Radix36IdConverter PAD_START = new Radix36IdConverter(true, MAX_CHAR_SIZE);
/**
- * Return an instance representing the specified parameter.
- * If new instances are not required, static cached instances are used to provide space and time efficiency.
+ * Gets an instance with specified parameters.
*
- * @param padStart padStart
- * @param charSize Size
- * @return Radix62IdConverter
+ * @param padStart whether to pad
+ * @param charSize character size
+ * @return converter instance
*/
public static Radix36IdConverter of(boolean padStart, int charSize) {
@@ -47,6 +61,12 @@ public static Radix36IdConverter of(boolean padStart, int charSize) {
return new Radix36IdConverter(padStart, charSize);
}
+ /**
+ * Creates a new converter.
+ *
+ * @param padStart whether to pad with leading zeros
+ * @param charSize the character size
+ */
public Radix36IdConverter(boolean padStart, int charSize) {
super(padStart, charSize);
}
diff --git a/cosid-core/src/main/java/me/ahoo/cosid/converter/RadixIdConverter.java b/cosid-core/src/main/java/me/ahoo/cosid/converter/RadixIdConverter.java
index 4a0fa1d707..67467808d5 100644
--- a/cosid-core/src/main/java/me/ahoo/cosid/converter/RadixIdConverter.java
+++ b/cosid-core/src/main/java/me/ahoo/cosid/converter/RadixIdConverter.java
@@ -22,34 +22,48 @@
import org.jspecify.annotations.NonNull;
+/**
+ * Abstract base for radix-based ID converters.
+ *
+ * Converts between long IDs and string representations using various radixes
+ * (base 36, 62, etc.). Supports optional zero-padding for consistent string length.
+ *
+ * @author ahoo wang
+ */
public abstract class RadixIdConverter implements IdConverter {
/**
- * 48.
+ * Character '0' (ASCII 48).
*/
static final char ZERO = '0';
/**
- * 57.
+ * Character '9' (ASCII 57).
*/
static final char NINE = '9';
/**
- * 65.
+ * Character 'A' (ASCII 65).
*/
static final char UPPERCASE_A = 'A';
static final int UPPERCASE_OFFSET = 10;
/**
- * 90.
+ * Character 'Z' (ASCII 90).
*/
static final char UPPERCASE_Z = 'Z';
/**
- * 97.
+ * Character 'a' (ASCII 97).
*/
static final char LOWERCASE_A = 'a';
static final int LOWERCASE_OFFSET = 36;
/**
- * 122.
+ * Character 'z' (ASCII 122).
*/
static final char LOWERCASE_Z = 'z';
+ /**
+ * Character lookup table for radix conversion.
+ * Index 0-9: digits '0'-'9'
+ * Index 10-35: uppercase letters 'A'-'Z'
+ * Index 36-61: lowercase letters 'a'-'z'
+ */
static final char[] digits = {
/*
* offset: 0.
@@ -70,12 +84,21 @@ public abstract class RadixIdConverter implements IdConverter {
'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', LOWERCASE_Z,
};
+ /**
+ * Padding character for fixed-width output.
+ */
public static final char PAD_CHAR = ZERO;
private final boolean padStart;
private final int charSize;
private final long maxId;
+ /**
+ * Creates a new RadixIdConverter.
+ *
+ * @param padStart whether to pad output with leading zeros
+ * @param charSize the fixed character size for output
+ */
protected RadixIdConverter(boolean padStart, int charSize) {
Preconditions.checkArgument(charSize > 0 && charSize <= getMaxCharSize(), "charSize cannot be greater than MAX_CHAR_SIZE[%s]!", getMaxCharSize());
this.padStart = padStart;
@@ -87,6 +110,12 @@ protected RadixIdConverter(boolean padStart, int charSize) {
}
}
+ /**
+ * Gets the offset value for a digit character.
+ *
+ * @param digitChar the character to convert
+ * @return the offset value (0-61) or -1 if invalid
+ */
public static int offset(char digitChar) {
if (digitChar >= ZERO && digitChar <= NINE) {
return digitChar - ZERO;
@@ -100,6 +129,13 @@ public static int offset(char digitChar) {
return -1;
}
+ /**
+ * Calculates maximum character size for a given radix and bit count.
+ *
+ * @param radix the number base
+ * @param bits number of bits
+ * @return maximum characters needed
+ */
public static int maxCharSize(int radix, int bits) {
long maxId = ~(-1L << bits);
int divideTimes = 0;
@@ -114,16 +150,36 @@ boolean isPadStart() {
return padStart;
}
+ /**
+ * Gets the fixed character size.
+ *
+ * @return character size
+ */
public int getCharSize() {
return charSize;
}
+ /**
+ * Gets the maximum ID representable with this char size.
+ *
+ * @return maximum ID
+ */
public long getMaxId() {
return maxId;
}
+ /**
+ * Gets the radix (base) for this converter.
+ *
+ * @return radix value
+ */
abstract int getRadix();
+ /**
+ * Gets the maximum character size for this converter type.
+ *
+ * @return maximum character size
+ */
abstract int getMaxCharSize();
@Override
diff --git a/cosid-core/src/main/java/me/ahoo/cosid/converter/SnowflakeFriendlyIdConverter.java b/cosid-core/src/main/java/me/ahoo/cosid/converter/SnowflakeFriendlyIdConverter.java
index 91dd8aa947..38666be87f 100644
--- a/cosid-core/src/main/java/me/ahoo/cosid/converter/SnowflakeFriendlyIdConverter.java
+++ b/cosid-core/src/main/java/me/ahoo/cosid/converter/SnowflakeFriendlyIdConverter.java
@@ -22,20 +22,36 @@
import org.jspecify.annotations.NonNull;
/**
- * Snowflake FriendlyId Converter.
+ * Converts Snowflake IDs to human-readable string format.
+ *
+ * Provides friendly string representations of Snowflake IDs
+ * with embedded timestamp and machine information.
*
* @author ahoo wang
*/
public class SnowflakeFriendlyIdConverter implements IdConverter {
+ /**
+ * Shared instance using millisecond parser.
+ */
public static final IdConverter INSTANCE = new SnowflakeFriendlyIdConverter(MillisecondSnowflakeIdStateParser.INSTANCE);
private final SnowflakeIdStateParser snowflakeIdStateParser;
+ /**
+ * Creates a converter with the specified parser.
+ *
+ * @param snowflakeIdStateParser the Snowflake ID state parser
+ */
public SnowflakeFriendlyIdConverter(SnowflakeIdStateParser snowflakeIdStateParser) {
this.snowflakeIdStateParser = snowflakeIdStateParser;
}
+ /**
+ * Gets the parser.
+ *
+ * @return the parser
+ */
public SnowflakeIdStateParser getParser() {
return snowflakeIdStateParser;
}
diff --git a/cosid-core/src/main/java/me/ahoo/cosid/converter/SuffixIdConverter.java b/cosid-core/src/main/java/me/ahoo/cosid/converter/SuffixIdConverter.java
index d6d46835d5..8a46665a77 100644
--- a/cosid-core/src/main/java/me/ahoo/cosid/converter/SuffixIdConverter.java
+++ b/cosid-core/src/main/java/me/ahoo/cosid/converter/SuffixIdConverter.java
@@ -22,7 +22,7 @@
import org.jspecify.annotations.NonNull;
/**
- * Suffix IdConverter .
+ * Converter that appends a fixed suffix to string IDs.
*
* @author ahoo wang
*/
@@ -30,6 +30,12 @@ public class SuffixIdConverter implements IdConverter, Decorator Optionally pads the string with leading zeros to a specified length.
*
* @author ahoo wang
*/
public class ToStringIdConverter implements IdConverter {
+ /**
+ * Shared instance without padding.
+ */
public static final ToStringIdConverter INSTANCE = new ToStringIdConverter(false, 0);
private final boolean padStart;
private final int charSize;
+ /**
+ * Creates a converter with optional padding.
+ *
+ * @param padStart whether to pad with leading zeros
+ * @param charSize the target character size for padding
+ */
public ToStringIdConverter(boolean padStart, int charSize) {
this.padStart = padStart;
this.charSize = charSize;
diff --git a/cosid-core/src/main/java/me/ahoo/cosid/cosid/CosIdIdStateParser.java b/cosid-core/src/main/java/me/ahoo/cosid/cosid/CosIdIdStateParser.java
index 1e57ba2048..3ae7bd50d6 100644
--- a/cosid-core/src/main/java/me/ahoo/cosid/cosid/CosIdIdStateParser.java
+++ b/cosid-core/src/main/java/me/ahoo/cosid/cosid/CosIdIdStateParser.java
@@ -15,16 +15,38 @@
/**
* Parser for converting {@link CosIdState} to String and vice versa.
- *
- * The {@link CosIdState} is a composite of timestamp, machineId, and sequence.
- * The {@link CosIdState} is a composite of timestamp, machineId, and sequence.
+ * This parser handles bidirectional conversion between the state object and string representations.
+ *
+ * @author ahoo wang
*/
public interface CosIdIdStateParser {
-
+
+ /**
+ * Parses a string representation into a CosIdState.
+ *
+ * @param id the string ID to parse
+ * @return the parsed CosIdState
+ */
CosIdState asState(String id);
-
+
+ /**
+ * Converts timestamp, machineId, and sequence to a string.
+ *
+ * @param lastTimestamp the timestamp in milliseconds
+ * @param machineId the machine ID
+ * @param sequence the sequence number
+ * @return string representation
+ */
String asString(long lastTimestamp, int machineId, int sequence);
-
+
+ /**
+ * Converts a CosIdState to its string representation.
+ *
+ * @param cosIdState the state to convert
+ * @return string representation
+ */
default String asString(CosIdState cosIdState) {
return asString(cosIdState.getTimestamp(), cosIdState.getMachineId(), cosIdState.getSequence());
}
diff --git a/cosid-core/src/main/java/me/ahoo/cosid/cosid/CosIdState.java b/cosid-core/src/main/java/me/ahoo/cosid/cosid/CosIdState.java
index 152c6f83fc..22b52c64ea 100644
--- a/cosid-core/src/main/java/me/ahoo/cosid/cosid/CosIdState.java
+++ b/cosid-core/src/main/java/me/ahoo/cosid/cosid/CosIdState.java
@@ -18,34 +18,62 @@
import java.util.Objects;
/**
- * CosId State.
- *
- * The {@link CosIdState} is a composite of timestamp, machineId, and sequence.
- * A CosId is composed of three components:
+ * Extends RadixCosIdGenerator with a FriendlyIdStateParser that generates
+ * IDs in format: {@code yyyyMMddHHmmssSSS-machineId-sequence}
+ *
+ * @author ahoo wang
+ */
public class FriendlyCosIdGenerator extends RadixCosIdGenerator {
+ /**
+ * Creates a generator with default bit configuration.
+ *
+ * @param machineId the machine ID
+ * @param zoneId time zone for timestamp formatting
+ * @param padStart whether to pad numbers with leading zeros
+ */
public FriendlyCosIdGenerator(int machineId, ZoneId zoneId, boolean padStart) {
this(DEFAULT_TIMESTAMP_BIT, DEFAULT_MACHINE_BIT, DEFAULT_SEQUENCE_BIT, machineId, DEFAULT_SEQUENCE_RESET_THRESHOLD, zoneId, padStart);
}
+ /**
+ * Creates a generator with custom bit configuration.
+ *
+ * @param timestampBit number of bits for timestamp
+ * @param machineIdBit number of bits for machine ID
+ * @param sequenceBit number of bits for sequence
+ * @param machineId the machine ID
+ * @param sequenceResetThreshold threshold for resetting sequence
+ * @param zoneId time zone for timestamp formatting
+ * @param padStart whether to pad numbers with leading zeros
+ */
public FriendlyCosIdGenerator(int timestampBit, int machineIdBit, int sequenceBit, int machineId, int sequenceResetThreshold, ZoneId zoneId, boolean padStart) {
super(timestampBit, machineIdBit, sequenceBit, machineId, sequenceResetThreshold, new FriendlyIdStateParser(zoneId, padStart, machineIdBit, sequenceBit));
}
diff --git a/cosid-core/src/main/java/me/ahoo/cosid/cosid/FriendlyIdStateParser.java b/cosid-core/src/main/java/me/ahoo/cosid/cosid/FriendlyIdStateParser.java
index b93de399e6..d8b1d5bf5f 100644
--- a/cosid-core/src/main/java/me/ahoo/cosid/cosid/FriendlyIdStateParser.java
+++ b/cosid-core/src/main/java/me/ahoo/cosid/cosid/FriendlyIdStateParser.java
@@ -35,12 +35,27 @@
import java.time.format.DateTimeFormatterBuilder;
import java.util.List;
+/**
+ * Parser for CosIdState using a human-readable format.
+ *
+ * Converts CosIdState to/from format: {@code yyyyMMddHHmmssSSS-machineId-sequence}
+ * Example: {@code 20210623131730192-1-0}
+ *
+ * @author ahoo wang
+ */
public class FriendlyIdStateParser implements CosIdIdStateParser {
+ /**
+ * Decimal radix for character size calculation.
+ */
public static final int DECIMAL_RADIX = 10;
private final ZoneId zoneId;
private final boolean padStart;
+ /**
+ * DateTimeFormatter for parsing/generating timestamp strings.
+ * Format: {@code yyyyMMddHHmmssSSS}
+ */
public static final DateTimeFormatter DATE_TIME_FORMATTER = new DateTimeFormatterBuilder()
.appendValue(YEAR, 4)
.appendValue(MONTH_OF_YEAR, 2)
@@ -54,6 +69,14 @@ public class FriendlyIdStateParser implements CosIdIdStateParser {
private final int machineCharSize;
private final int sequenceCharSize;
+ /**
+ * Creates a new FriendlyIdStateParser.
+ *
+ * @param zoneId time zone for timestamp conversion
+ * @param padStart whether to pad numbers with leading zeros
+ * @param machineBit number of bits for machine ID
+ * @param sequenceBit number of bits for sequence
+ */
public FriendlyIdStateParser(ZoneId zoneId, boolean padStart, int machineBit, int sequenceBit) {
this.zoneId = zoneId;
this.padStart = padStart;
@@ -74,6 +97,14 @@ public CosIdState asState(String id) {
return new CosIdState(timestamp, machineId, sequence);
}
+ /**
+ * Converts an integer to string with optional padding.
+ *
+ * @param padStart whether to pad with leading zeros
+ * @param value the value to convert
+ * @param charSize the minimum character size
+ * @return the formatted string
+ */
public static String intAsString(boolean padStart, int value, int charSize) {
if (padStart) {
return Strings.padStart(String.valueOf(value), charSize, PAD_CHAR);
diff --git a/cosid-core/src/main/java/me/ahoo/cosid/cosid/Radix36CosIdGenerator.java b/cosid-core/src/main/java/me/ahoo/cosid/cosid/Radix36CosIdGenerator.java
index 6b4535e09c..b5cbd002b4 100644
--- a/cosid-core/src/main/java/me/ahoo/cosid/cosid/Radix36CosIdGenerator.java
+++ b/cosid-core/src/main/java/me/ahoo/cosid/cosid/Radix36CosIdGenerator.java
@@ -14,16 +14,35 @@
package me.ahoo.cosid.cosid;
/**
- * [timestamp(44)]-[machineId-(20)]-[sequence-(16)] = 80 BITS = 17 CHARS.
+ * CosIdGenerator using radix-36 string encoding.
+ *
+ * Encodes IDs using characters 0-9 and A-Z (36 characters).
+ * Bit allocation: timestamp(44) + machineId(20) + sequence(16) = 80 bits = 17 chars.
+ *
+ * @author ahoo wang
*/
public class Radix36CosIdGenerator extends RadixCosIdGenerator {
+ /**
+ * Creates a generator with default configuration.
+ *
+ * @param machineId the machine ID
+ */
public Radix36CosIdGenerator(int machineId) {
this(DEFAULT_TIMESTAMP_BIT, DEFAULT_MACHINE_BIT, DEFAULT_SEQUENCE_BIT, machineId, DEFAULT_SEQUENCE_RESET_THRESHOLD);
}
-
+
+ /**
+ * Creates a generator with custom configuration.
+ *
+ * @param timestampBit number of bits for timestamp
+ * @param machineIdBit number of bits for machine ID
+ * @param sequenceBit number of bits for sequence
+ * @param machineId the machine ID
+ * @param sequenceResetThreshold threshold for resetting sequence
+ */
public Radix36CosIdGenerator(int timestampBit, int machineIdBit, int sequenceBit, int machineId, int sequenceResetThreshold) {
super(timestampBit, machineIdBit, sequenceBit, machineId, sequenceResetThreshold, RadixCosIdStateParser.ofRadix36(timestampBit, machineIdBit, sequenceBit));
}
-
+
}
diff --git a/cosid-core/src/main/java/me/ahoo/cosid/cosid/Radix62CosIdGenerator.java b/cosid-core/src/main/java/me/ahoo/cosid/cosid/Radix62CosIdGenerator.java
index 9ca7965f73..e17c92e9e5 100644
--- a/cosid-core/src/main/java/me/ahoo/cosid/cosid/Radix62CosIdGenerator.java
+++ b/cosid-core/src/main/java/me/ahoo/cosid/cosid/Radix62CosIdGenerator.java
@@ -14,16 +14,35 @@
package me.ahoo.cosid.cosid;
/**
- * [timestamp(44)]-[machineId-(20)]-[sequence-(16)] = 80 BITS = 15 CHARS.
+ * CosIdGenerator using radix-62 string encoding.
+ *
+ * Encodes IDs using characters 0-9, A-Z, and a-z (62 characters).
+ * Bit allocation: timestamp(44) + machineId(20) + sequence(16) = 80 bits = 15 chars.
+ *
+ * @author ahoo wang
*/
public class Radix62CosIdGenerator extends RadixCosIdGenerator {
-
+
+ /**
+ * Creates a generator with default configuration.
+ *
+ * @param machineId the machine ID
+ */
public Radix62CosIdGenerator(int machineId) {
this(DEFAULT_TIMESTAMP_BIT, DEFAULT_MACHINE_BIT, DEFAULT_SEQUENCE_BIT, machineId, DEFAULT_SEQUENCE_RESET_THRESHOLD);
}
-
+
+ /**
+ * Creates a generator with custom configuration.
+ *
+ * @param timestampBit number of bits for timestamp
+ * @param machineIdBit number of bits for machine ID
+ * @param sequenceBit number of bits for sequence
+ * @param machineId the machine ID
+ * @param sequenceResetThreshold threshold for resetting sequence
+ */
public Radix62CosIdGenerator(int timestampBit, int machineIdBit, int sequenceBit, int machineId, int sequenceResetThreshold) {
super(timestampBit, machineIdBit, sequenceBit, machineId, sequenceResetThreshold, RadixCosIdStateParser.ofRadix62(timestampBit, machineIdBit, sequenceBit));
}
-
+
}
diff --git a/cosid-core/src/main/java/me/ahoo/cosid/cosid/RadixCosIdGenerator.java b/cosid-core/src/main/java/me/ahoo/cosid/cosid/RadixCosIdGenerator.java
index adce8ba288..8f028ab21b 100644
--- a/cosid-core/src/main/java/me/ahoo/cosid/cosid/RadixCosIdGenerator.java
+++ b/cosid-core/src/main/java/me/ahoo/cosid/cosid/RadixCosIdGenerator.java
@@ -20,11 +20,12 @@
import org.jspecify.annotations.NonNull;
/**
- * Radix CosIdGenerator.
- *
- * It's a simple implementation of {@link CosIdGenerator}.
- * A simpler variant of Snowflake ID that uses configurable bit allocation
+ * for timestamp, machine ID, and sequence components.
+ *
+ * @author ahoo wang
* @see CosIdGenerator
* @see CosIdIdStateParser
* @see CosIdState
@@ -32,22 +33,44 @@
* @see TimestampOverflowException
*/
public class RadixCosIdGenerator implements CosIdGenerator {
+ /**
+ * Default timestamp bits (44 bits, ~556 years at millisecond precision).
+ */
public static final int DEFAULT_TIMESTAMP_BIT = 44;
+ /**
+ * Default machine ID bits (20 bits).
+ */
public static final int DEFAULT_MACHINE_BIT = 20;
+ /**
+ * Default sequence bits (16 bits, 65536 per millisecond).
+ */
public static final int DEFAULT_SEQUENCE_BIT = 16;
+ /**
+ * Default sequence reset threshold (half of max sequence).
+ */
public static final int DEFAULT_SEQUENCE_RESET_THRESHOLD = ~(-1 << (DEFAULT_SEQUENCE_BIT - 1));
-
+
private final long maxTimestamp;
private final int maxMachine;
private final int maxSequence;
private final int sequenceResetThreshold;
-
+
private final int machineId;
private int sequence = 0;
private long lastTimestamp = -1L;
-
+
private final CosIdIdStateParser stateParser;
-
+
+ /**
+ * Creates a new RadixCosIdGenerator.
+ *
+ * @param timestampBit number of bits for timestamp
+ * @param machineIdBit number of bits for machine ID
+ * @param sequenceBit number of bits for sequence
+ * @param machineId the machine ID
+ * @param sequenceResetThreshold threshold for resetting sequence
+ * @param stateParser the state parser for string conversion
+ */
public RadixCosIdGenerator(int timestampBit,
int machineIdBit,
int sequenceBit,
@@ -64,23 +87,23 @@ public RadixCosIdGenerator(int timestampBit,
this.machineId = machineId;
this.stateParser = stateParser;
}
-
+
@Override
public int getMachineId() {
return machineId;
}
-
+
@Override
public long getLastTimestamp() {
return lastTimestamp;
}
-
+
@NonNull
@Override
public CosIdIdStateParser getStateParser() {
return stateParser;
}
-
+
private long nextTime() {
long time = System.currentTimeMillis();
while (time <= lastTimestamp) {
@@ -88,29 +111,34 @@ private long nextTime() {
}
return time;
}
-
+
+ /**
+ * Generates the next ID as a state object.
+ *
+ * @return the generated CosIdState
+ */
@NonNull
public synchronized CosIdState generateAsState() {
long currentTimestamp = System.currentTimeMillis();
if (currentTimestamp < lastTimestamp) {
throw new ClockBackwardsException(lastTimestamp, currentTimestamp);
}
-
+
//region Reset sequence based on sequence reset threshold,Optimize the problem of uneven sharding.
-
+
if (currentTimestamp > lastTimestamp
&& sequence >= sequenceResetThreshold) {
sequence = 0;
}
-
+
sequence = (sequence + 1) & maxSequence;
-
+
if (sequence == 0) {
currentTimestamp = nextTime();
}
-
+
//endregion
-
+
if (currentTimestamp > maxTimestamp) {
throw new TimestampOverflowException(0, currentTimestamp, maxTimestamp);
}
diff --git a/cosid-core/src/main/java/me/ahoo/cosid/jvm/AtomicLongGenerator.java b/cosid-core/src/main/java/me/ahoo/cosid/jvm/AtomicLongGenerator.java
index 95f947dec6..2f532cf57a 100644
--- a/cosid-core/src/main/java/me/ahoo/cosid/jvm/AtomicLongGenerator.java
+++ b/cosid-core/src/main/java/me/ahoo/cosid/jvm/AtomicLongGenerator.java
@@ -18,11 +18,17 @@
import java.util.concurrent.atomic.AtomicLong;
/**
- * AtomicLong Generator.
+ * AtomicLong-based ID generator.
+ *
+ * Generates unique IDs using an atomic counter.
+ * Thread-safe and suitable for single-JVM ID generation.
*
* @author ahoo wang
*/
public class AtomicLongGenerator implements IdGenerator {
+ /**
+ * Shared singleton instance.
+ */
public static final IdGenerator INSTANCE = new AtomicLongGenerator();
private final AtomicLong idGen = new AtomicLong();
diff --git a/cosid-core/src/main/java/me/ahoo/cosid/jvm/UuidGenerator.java b/cosid-core/src/main/java/me/ahoo/cosid/jvm/UuidGenerator.java
index 208c0a0972..66cd52a73f 100644
--- a/cosid-core/src/main/java/me/ahoo/cosid/jvm/UuidGenerator.java
+++ b/cosid-core/src/main/java/me/ahoo/cosid/jvm/UuidGenerator.java
@@ -22,10 +22,16 @@
/**
* UUID ID Generator.
*
+ * Generates UUIDs as string representations.
+ * Note: Does not support {@link #generate()} for long IDs.
+ *
* @author ahoo wang
*/
public class UuidGenerator implements IdGenerator {
+ /**
+ * Shared singleton instance.
+ */
public static final IdGenerator INSTANCE = new UuidGenerator();
@Override
diff --git a/cosid-core/src/main/java/me/ahoo/cosid/machine/ClockBackwardsSynchronizer.java b/cosid-core/src/main/java/me/ahoo/cosid/machine/ClockBackwardsSynchronizer.java
index 4cec05fc3b..3e83a3709c 100644
--- a/cosid-core/src/main/java/me/ahoo/cosid/machine/ClockBackwardsSynchronizer.java
+++ b/cosid-core/src/main/java/me/ahoo/cosid/machine/ClockBackwardsSynchronizer.java
@@ -18,18 +18,43 @@
import com.google.errorprone.annotations.ThreadSafe;
/**
- * Clock Backwards Synchronizer.
+ * Synchronizer for handling clock backwards issues in Snowflake ID generation.
+ *
+ * When system clock moves backwards, this synchronizer waits until
+ * the clock catches up to ensure unique IDs.
*
* @author ahoo wang
*/
@ThreadSafe
public interface ClockBackwardsSynchronizer {
+ /**
+ * Default synchronizer instance.
+ */
ClockBackwardsSynchronizer DEFAULT = new DefaultClockBackwardsSynchronizer();
+ /**
+ * Synchronizes clock by waiting until current time exceeds lastTimestamp.
+ *
+ * @param lastTimestamp the last timestamp that was generated
+ * @throws InterruptedException if thread is interrupted while waiting
+ * @throws ClockTooManyBackwardsException if clock backwards exceeds threshold
+ */
void sync(long lastTimestamp) throws InterruptedException, ClockTooManyBackwardsException;
+ /**
+ * Synchronizes clock without throwing InterruptedException.
+ *
+ * @param lastTimestamp the last timestamp that was generated
+ * @throws ClockTooManyBackwardsException if clock backwards exceeds threshold
+ */
void syncUninterruptibly(long lastTimestamp) throws ClockTooManyBackwardsException;
+ /**
+ * Calculates how far backwards the clock has moved.
+ *
+ * @param lastTimestamp the last timestamp
+ * @return the backwards duration in milliseconds
+ */
static long getBackwardsTimeStamp(long lastTimestamp) {
return lastTimestamp - System.currentTimeMillis();
}
diff --git a/cosid-core/src/main/java/me/ahoo/cosid/machine/HostAddressSupplier.java b/cosid-core/src/main/java/me/ahoo/cosid/machine/HostAddressSupplier.java
index 4448b56c96..fa257ee78b 100644
--- a/cosid-core/src/main/java/me/ahoo/cosid/machine/HostAddressSupplier.java
+++ b/cosid-core/src/main/java/me/ahoo/cosid/machine/HostAddressSupplier.java
@@ -13,8 +13,18 @@
package me.ahoo.cosid.machine;
+/**
+ * Functional interface for providing host address.
+ *
+ * @author ahoo wang
+ */
@FunctionalInterface
public interface HostAddressSupplier {
+ /**
+ * Gets the host address.
+ *
+ * @return the host address
+ */
String getHostAddress();
}
diff --git a/cosid-core/src/main/java/me/ahoo/cosid/machine/InMemoryMachineStateStorage.java b/cosid-core/src/main/java/me/ahoo/cosid/machine/InMemoryMachineStateStorage.java
index d7cc5c113c..baa62d6c9d 100644
--- a/cosid-core/src/main/java/me/ahoo/cosid/machine/InMemoryMachineStateStorage.java
+++ b/cosid-core/src/main/java/me/ahoo/cosid/machine/InMemoryMachineStateStorage.java
@@ -18,15 +18,24 @@
import java.util.concurrent.ConcurrentHashMap;
+/**
+ * In-memory implementation of {@link MachineStateStorage}.
+ *
+ * Stores machine states in a {@link ConcurrentHashMap} for fast access.
+ * This implementation is not persistent and should only be used for testing
+ * or single-instance deployments.
+ *
+ * @author ahoo wang
+ */
@Slf4j
public class InMemoryMachineStateStorage implements MachineStateStorage {
private final ConcurrentHashMap An InstanceId identifies a particular running instance of a service, which may
+ * be part of a deployment that provides stable machine IDs (stable=true) or a
+ * dynamic instance where machine IDs may change (stable=false).
*
* @author ahoo wang
* @see MachineId
*/
@Immutable
public class InstanceId {
+ /**
+ * Sentinel value representing no instance.
+ */
public static final InstanceId NONE = new InstanceId("none", false);
-
+
private final String instanceId;
private final boolean stable;
-
+
+ /**
+ * Creates a new InstanceId.
+ *
+ * @param instanceId the instance identifier string
+ * @param stable whether this instance has a stable identity
+ */
public InstanceId(String instanceId, boolean stable) {
this.instanceId = instanceId;
this.stable = stable;
}
-
+
/**
- * 稳定的的实例拥有稳定的机器号.
+ * Checks if this instance has a stable identity.
+ *
+ * Stable instances (stable=true) are deployed with stable identities (e.g., Kubernetes StatefulSet)
+ * and can rely on having consistent machine IDs across restarts.
*
- * @return Is the instance deployment status stable?
+ * @return true if the instance has a stable identity
*/
public boolean isStable() {
return stable;
}
-
+
+ /**
+ * Gets the instance identifier string.
+ *
+ * @return the instance ID
+ */
public String getInstanceId() {
return instanceId;
}
-
+
@Override
public String toString() {
return MoreObjects.toStringHelper(this)
@@ -55,16 +76,31 @@ public String toString() {
.add("stable", stable)
.toString();
}
-
+
+ /**
+ * Creates an InstanceId from host and port.
+ *
+ * @param host the host address
+ * @param port the port number
+ * @param stable whether this instance has a stable identity
+ * @return a new InstanceId
+ */
public static InstanceId of(String host, int port, boolean stable) {
String instanceIdStr = String.format("%s:%s", host, port);
return of(instanceIdStr, stable);
}
-
+
+ /**
+ * Creates an InstanceId from an instance ID string.
+ *
+ * @param instanceId the instance identifier
+ * @param stable whether this instance has a stable identity
+ * @return a new InstanceId
+ */
public static InstanceId of(String instanceId, boolean stable) {
return new InstanceId(instanceId, stable);
}
-
+
@Override
public boolean equals(Object o) {
if (this == o) {
@@ -76,7 +112,7 @@ public boolean equals(Object o) {
InstanceId that = (InstanceId) o;
return stable == that.stable && Objects.equal(instanceId, that.instanceId);
}
-
+
@Override
public int hashCode() {
return Objects.hashCode(instanceId, stable);
diff --git a/cosid-core/src/main/java/me/ahoo/cosid/machine/LocalMachineStateStorage.java b/cosid-core/src/main/java/me/ahoo/cosid/machine/LocalMachineStateStorage.java
index b4950a829b..9aa45ce616 100644
--- a/cosid-core/src/main/java/me/ahoo/cosid/machine/LocalMachineStateStorage.java
+++ b/cosid-core/src/main/java/me/ahoo/cosid/machine/LocalMachineStateStorage.java
@@ -29,19 +29,36 @@
import java.nio.file.Paths;
/**
- * LocalMachine State Storage.
+ * File-based machine state storage.
+ *
+ * Stores machine state in local files, using base64-encoded
+ * filenames for namespace/instance encoding.
*
* @author ahoo wang
*/
@Slf4j
public class LocalMachineStateStorage implements MachineStateStorage {
+ /**
+ * Default state location in user home directory.
+ */
public static final String DEFAULT_STATE_LOCATION_PATH = Paths.get(System.getProperty("user.home"), ".cosid-machine-state").toString();
+ /**
+ * The state location path.
+ */
public final String stateLocation;
+ /**
+ * Creates storage with specified location.
+ *
+ * @param stateLocation the directory path for state files
+ */
public LocalMachineStateStorage(String stateLocation) {
this.stateLocation = stateLocation;
}
+ /**
+ * Creates storage with default location.
+ */
public LocalMachineStateStorage() {
this(DEFAULT_STATE_LOCATION_PATH);
}
diff --git a/cosid-core/src/main/java/me/ahoo/cosid/machine/MachineId.java b/cosid-core/src/main/java/me/ahoo/cosid/machine/MachineId.java
index 790f4a4269..f943e836ed 100644
--- a/cosid-core/src/main/java/me/ahoo/cosid/machine/MachineId.java
+++ b/cosid-core/src/main/java/me/ahoo/cosid/machine/MachineId.java
@@ -17,7 +17,11 @@
import com.google.errorprone.annotations.Immutable;
/**
- * 逻辑概念的机器号,并不一定跟物理机/虚拟机一一对应,运行进程的唯一性编号(不同业务领域/服务使用 namespace 隔离).
+ * Logical machine identifier for distributed ID generation.
+ *
+ * This represents a logical machine ID that is not necessarily tied to a physical
+ * or virtual machine. It provides uniqueness across different processes/services
+ * which are isolated using namespaces.
*
* @author ahoo wang
* @see InstanceId
@@ -26,10 +30,20 @@
public class MachineId {
private final int machineId;
+ /**
+ * Creates a new MachineId.
+ *
+ * @param machineId the machine ID value
+ */
public MachineId(int machineId) {
this.machineId = machineId;
}
+ /**
+ * Gets the machine ID value.
+ *
+ * @return the machine ID
+ */
public int getMachineId() {
return machineId;
}
diff --git a/cosid-core/src/main/java/me/ahoo/cosid/machine/MachineIdLostException.java b/cosid-core/src/main/java/me/ahoo/cosid/machine/MachineIdLostException.java
index 9170d469e2..7447371bd3 100644
--- a/cosid-core/src/main/java/me/ahoo/cosid/machine/MachineIdLostException.java
+++ b/cosid-core/src/main/java/me/ahoo/cosid/machine/MachineIdLostException.java
@@ -19,7 +19,10 @@
import org.jspecify.annotations.Nullable;
/**
- * MachineId Lost Exception .
+ * Exception thrown when a machine ID is lost.
+ *
+ * Indicates that a machine ID that was previously allocated
+ * can no longer be found in the distributed store.
*
* @author ahoo wang
*/
@@ -27,22 +30,44 @@ public class MachineIdLostException extends CosIdException {
private final String namespace;
private final InstanceId instanceId;
private final MachineState machineState;
-
+
+ /**
+ * Creates a new exception.
+ *
+ * @param namespace the namespace
+ * @param instanceId the instance ID
+ * @param machineState the machine state (may be null)
+ */
public MachineIdLostException(String namespace, InstanceId instanceId, @Nullable MachineState machineState) {
super(Strings.lenientFormat("The machine id[%s] bound to the instance[%s]@[%s] has been lost!.", machineState, instanceId, namespace));
this.namespace = namespace;
this.instanceId = instanceId;
this.machineState = machineState;
}
-
+
+ /**
+ * Gets the namespace.
+ *
+ * @return the namespace
+ */
public String getNamespace() {
return namespace;
}
-
+
+ /**
+ * Gets the instance ID.
+ *
+ * @return the instance ID
+ */
public InstanceId getInstanceId() {
return instanceId;
}
-
+
+ /**
+ * Gets the machine state.
+ *
+ * @return the machine state
+ */
public MachineState getMachineState() {
return machineState;
}
diff --git a/cosid-core/src/main/java/me/ahoo/cosid/machine/MachineIdOverflowException.java b/cosid-core/src/main/java/me/ahoo/cosid/machine/MachineIdOverflowException.java
index 0429af4a52..8b086beb66 100644
--- a/cosid-core/src/main/java/me/ahoo/cosid/machine/MachineIdOverflowException.java
+++ b/cosid-core/src/main/java/me/ahoo/cosid/machine/MachineIdOverflowException.java
@@ -18,7 +18,10 @@
import com.google.common.base.Strings;
/**
- * MachineId Overflow Exception.
+ * Exception thrown when machine ID cannot be allocated.
+ *
+ * Indicates that all available machine IDs have been allocated
+ * and no more can be distributed.
*
* @author ahoo wang
*/
@@ -26,16 +29,32 @@ public class MachineIdOverflowException extends CosIdException {
private final int totalMachineIds;
private final InstanceId instanceId;
+ /**
+ * Creates a new exception.
+ *
+ * @param totalMachineIds the total number of available machine IDs
+ * @param instanceId the instance that failed to get an ID
+ */
public MachineIdOverflowException(int totalMachineIds, InstanceId instanceId) {
super(Strings.lenientFormat("InstanceId:[%s] - distribution failed - totalMachineIds:[%s]", instanceId, totalMachineIds));
this.totalMachineIds = totalMachineIds;
this.instanceId = instanceId;
}
+ /**
+ * Gets the total number of machine IDs.
+ *
+ * @return the total machine IDs
+ */
public int getTotalMachineIds() {
return totalMachineIds;
}
+ /**
+ * Gets the instance ID.
+ *
+ * @return the instance ID
+ */
public InstanceId getInstanceId() {
return instanceId;
}
diff --git a/cosid-core/src/main/java/me/ahoo/cosid/machine/MachineStateStorage.java b/cosid-core/src/main/java/me/ahoo/cosid/machine/MachineStateStorage.java
index e453b459c9..bf12b73353 100644
--- a/cosid-core/src/main/java/me/ahoo/cosid/machine/MachineStateStorage.java
+++ b/cosid-core/src/main/java/me/ahoo/cosid/machine/MachineStateStorage.java
@@ -17,25 +17,73 @@
import org.jspecify.annotations.NonNull;
/**
- * Machine State Storage.
+ * Machine state storage for persisting machine state across restarts.
+ *
+ * Provides an interface for storing and retrieving machine state information,
+ * which is essential for maintaining machine ID allocations in distributed
+ * ID generation systems.
*
* @author ahoo wang
*/
@ThreadSafe
public interface MachineStateStorage {
+ /**
+ * Local machine state storage instance.
+ */
MachineStateStorage LOCAL = new LocalMachineStateStorage();
+ /**
+ * In-memory machine state storage instance.
+ */
MachineStateStorage IN_MEMORY = new InMemoryMachineStateStorage();
+ /**
+ * Gets the machine state for a given namespace and instance.
+ *
+ * @param namespace the namespace
+ * @param instanceId the instance ID
+ * @return the machine state, or NOT_FOUND if not found
+ */
@NonNull
MachineState get(String namespace, InstanceId instanceId);
+ /**
+ * Sets the machine state for a given namespace and instance.
+ *
+ * @param namespace the namespace
+ * @param machineId the machine ID
+ * @param instanceId the instance ID
+ */
void set(String namespace, int machineId, InstanceId instanceId);
+ /**
+ * Removes the machine state for a given namespace and instance.
+ *
+ * @param namespace the namespace
+ * @param instanceId the instance ID
+ */
void remove(String namespace, InstanceId instanceId);
+ /**
+ * Clears all machine states for a given namespace.
+ *
+ * @param namespace the namespace
+ */
void clear(String namespace);
+ /**
+ * Gets the number of machine states in a namespace.
+ *
+ * @param namespace the namespace
+ * @return the number of machine states
+ */
int size(String namespace);
+ /**
+ * Checks if a machine state exists for a given namespace and instance.
+ *
+ * @param namespace the namespace
+ * @param instanceId the instance ID
+ * @return true if the state exists
+ */
boolean exists(String namespace, InstanceId instanceId);
}
diff --git a/cosid-core/src/main/java/me/ahoo/cosid/machine/ManualMachineIdDistributor.java b/cosid-core/src/main/java/me/ahoo/cosid/machine/ManualMachineIdDistributor.java
index e78812c3d5..24ad5640c7 100644
--- a/cosid-core/src/main/java/me/ahoo/cosid/machine/ManualMachineIdDistributor.java
+++ b/cosid-core/src/main/java/me/ahoo/cosid/machine/ManualMachineIdDistributor.java
@@ -18,26 +18,41 @@
import java.time.Duration;
/**
- * Manual Machine Id Distributor.
+ * Manual machine ID distributor.
+ *
+ * Uses a manually configured machine ID instead of dynamically
+ * distributing from a centralized store.
*
* @author ahoo wang
*/
@Slf4j
public class ManualMachineIdDistributor extends AbstractMachineIdDistributor {
-
+
private final int machineId;
private final MachineState machineState;
-
+
+ /**
+ * Creates a manual distributor.
+ *
+ * @param machineId the fixed machine ID to use
+ * @param machineStateStorage the state storage
+ * @param clockBackwardsSynchronizer the clock synchronizer
+ */
public ManualMachineIdDistributor(int machineId, MachineStateStorage machineStateStorage, ClockBackwardsSynchronizer clockBackwardsSynchronizer) {
super(machineStateStorage, clockBackwardsSynchronizer);
this.machineId = machineId;
this.machineState = MachineState.of(machineId, NOT_FOUND_LAST_STAMP);
}
-
+
+ /**
+ * Gets the machine ID.
+ *
+ * @return the machine ID
+ */
public int getMachineId() {
return machineId;
}
-
+
@Override
protected MachineState distributeRemote(String namespace, int machineBit, InstanceId instanceId, Duration safeGuardDuration) {
if (log.isInfoEnabled()) {
@@ -45,16 +60,16 @@ protected MachineState distributeRemote(String namespace, int machineBit, Instan
}
return machineState;
}
-
+
@Override
protected void revertRemote(String namespace, InstanceId instanceId, MachineState machineState) {
-
+
}
-
+
@Override
protected void guardRemote(String namespace, InstanceId instanceId, MachineState machineState, Duration safeGuardDuration) {
-
+
}
-
-
+
+
}
diff --git a/cosid-core/src/main/java/me/ahoo/cosid/machine/NamespacedInstanceId.java b/cosid-core/src/main/java/me/ahoo/cosid/machine/NamespacedInstanceId.java
index 46e619431f..304caf0985 100644
--- a/cosid-core/src/main/java/me/ahoo/cosid/machine/NamespacedInstanceId.java
+++ b/cosid-core/src/main/java/me/ahoo/cosid/machine/NamespacedInstanceId.java
@@ -17,28 +17,47 @@
import com.google.common.base.Objects;
/**
- * NamespacedInstanceId .
+ * Combines namespace with instance ID for unique identification.
+ *
+ * Used to ensure machine IDs are unique across different
+ * namespaces/business domains.
*
* @author ahoo wang
*/
public class NamespacedInstanceId {
private final String namespace;
-
+
private final InstanceId instanceId;
-
+
+ /**
+ * Creates a new namespaced instance ID.
+ *
+ * @param namespace the namespace
+ * @param instanceId the instance ID
+ */
public NamespacedInstanceId(String namespace, InstanceId instanceId) {
this.namespace = namespace;
this.instanceId = instanceId;
}
-
+
+ /**
+ * Gets the namespace.
+ *
+ * @return the namespace
+ */
public String getNamespace() {
return namespace;
}
-
+
+ /**
+ * Gets the instance ID.
+ *
+ * @return the instance ID
+ */
public InstanceId getInstanceId() {
return instanceId;
}
-
+
@Override
public boolean equals(Object o) {
if (this == o) {
@@ -50,12 +69,12 @@ public boolean equals(Object o) {
NamespacedInstanceId that = (NamespacedInstanceId) o;
return Objects.equal(getNamespace(), that.getNamespace()) && Objects.equal(getInstanceId(), that.getInstanceId());
}
-
+
@Override
public int hashCode() {
return Objects.hashCode(getNamespace(), getInstanceId());
}
-
+
@Override
public String toString() {
return MoreObjects.toStringHelper(this)
diff --git a/cosid-core/src/main/java/me/ahoo/cosid/machine/NotFoundMachineStateException.java b/cosid-core/src/main/java/me/ahoo/cosid/machine/NotFoundMachineStateException.java
index c612085db3..abca1c82c6 100644
--- a/cosid-core/src/main/java/me/ahoo/cosid/machine/NotFoundMachineStateException.java
+++ b/cosid-core/src/main/java/me/ahoo/cosid/machine/NotFoundMachineStateException.java
@@ -18,24 +18,43 @@
import com.google.common.base.Strings;
/**
- * NotFoundMachineStateException .
+ * Exception thrown when machine state is not found.
+ *
+ * Indicates that the machine state for a specific instance
+ * could not be found in the distributed store.
*
* @author ahoo wang
*/
public class NotFoundMachineStateException extends CosIdException {
private final String namespace;
private final InstanceId instanceId;
-
+
+ /**
+ * Creates a new exception.
+ *
+ * @param namespace the namespace
+ * @param instanceId the instance ID
+ */
public NotFoundMachineStateException(String namespace, InstanceId instanceId) {
super(Strings.lenientFormat("Not found the MachineState of instance[%s]@[%s]!", instanceId, namespace));
this.namespace = namespace;
this.instanceId = instanceId;
}
-
+
+ /**
+ * Gets the namespace.
+ *
+ * @return the namespace
+ */
public String getNamespace() {
return namespace;
}
-
+
+ /**
+ * Gets the instance ID.
+ *
+ * @return the instance ID
+ */
public InstanceId getInstanceId() {
return instanceId;
}
diff --git a/cosid-core/src/main/java/me/ahoo/cosid/provider/DefaultIdGeneratorProvider.java b/cosid-core/src/main/java/me/ahoo/cosid/provider/DefaultIdGeneratorProvider.java
index 0fdc6882ed..2bd40ae134 100644
--- a/cosid-core/src/main/java/me/ahoo/cosid/provider/DefaultIdGeneratorProvider.java
+++ b/cosid-core/src/main/java/me/ahoo/cosid/provider/DefaultIdGeneratorProvider.java
@@ -26,43 +26,52 @@
/**
* Default {@link IdGeneratorProvider} implementation.
*
+ * Thread-safe registry for managing named ID generator instances
+ * using a {@link ConcurrentHashMap} for concurrent access.
+ *
* @author ahoo wang
*/
@ThreadSafe
public class DefaultIdGeneratorProvider implements IdGeneratorProvider {
-
+
+ /**
+ * Shared singleton instance.
+ */
public static final IdGeneratorProvider INSTANCE = new DefaultIdGeneratorProvider();
private volatile IdGenerator shareIdGenerator;
-
+
private final ConcurrentHashMap Delays the lookup of an ID generator from the provider until first access.
+ * This is useful when the generator might not be immediately available at startup.
+ *
* @author ahoo wang
*/
public final class LazyIdGenerator implements IdGeneratorDecorator {
-
+
private final String generatorName;
-
+
private volatile IdGenerator lazyIdGen;
-
+
private final IdGeneratorProvider idGeneratorProvider;
-
+
+ /**
+ * Creates a lazy generator with default provider.
+ *
+ * @param generatorName the name of the generator to lookup
+ */
public LazyIdGenerator(String generatorName) {
this(generatorName, DefaultIdGeneratorProvider.INSTANCE);
}
-
+
+ /**
+ * Creates a lazy generator with custom provider.
+ *
+ * @param generatorName the name of the generator to lookup
+ * @param idGeneratorProvider the provider to use for lookup
+ */
public LazyIdGenerator(String generatorName, IdGeneratorProvider idGeneratorProvider) {
this.generatorName = generatorName;
this.idGeneratorProvider = idGeneratorProvider;
}
-
+
+ /**
+ * Gets the generator name.
+ *
+ * @return the generator name
+ */
public String getGeneratorName() {
return generatorName;
}
-
+
+ /**
+ * Attempts to get the generator, optionally throwing if not found.
+ *
+ * @param required if true, throws NotFoundIdGeneratorException if not found
+ * @return the generator or null if not required and not found
+ * @throws NotFoundIdGeneratorException if required and not found
+ */
public IdGenerator tryGet(boolean required) {
if (null != lazyIdGen) {
return lazyIdGen;
@@ -66,7 +92,14 @@ public IdGenerator tryGet(boolean required) {
}
return null;
}
-
+
+ /**
+ * Gets this generator as a SnowflakeId.
+ *
+ * @param required if true, throws if not a SnowflakeId
+ * @return the SnowflakeId or null
+ * @throws CosIdException if not a SnowflakeId when required
+ */
public SnowflakeId asSnowflakeId(boolean required) {
IdGenerator idGenerator = tryGet(required);
if (null == idGenerator) {
@@ -77,7 +110,14 @@ public SnowflakeId asSnowflakeId(boolean required) {
}
throw new CosIdException(Strings.lenientFormat("IdGenerator:[%s] is not instanceof SnowflakeId!", generatorName));
}
-
+
+ /**
+ * Gets this generator as a SnowflakeFriendlyId.
+ *
+ * @param required if true, throws if not a SnowflakeFriendlyId
+ * @return the SnowflakeFriendlyId or null
+ * @throws CosIdException if not a SnowflakeFriendlyId when required
+ */
public SnowflakeFriendlyId asFriendlyId(boolean required) {
IdGenerator idGenerator = tryGet(required);
if (null == idGenerator) {
@@ -88,7 +128,14 @@ public SnowflakeFriendlyId asFriendlyId(boolean required) {
}
throw new CosIdException(Strings.lenientFormat("IdGenerator:[%s] is not instanceof SnowflakeFriendlyId!", generatorName));
}
-
+
+ /**
+ * Gets this generator as a SegmentId.
+ *
+ * @param required if true, throws if not a SegmentId
+ * @return the SegmentId or null
+ * @throws CosIdException if not a SegmentId when required
+ */
public SegmentId asSegmentId(boolean required) {
IdGenerator idGenerator = tryGet(required);
if (null == idGenerator) {
@@ -99,12 +146,12 @@ public SegmentId asSegmentId(boolean required) {
}
throw new CosIdException(Strings.lenientFormat("IdGenerator:[%s] is not instanceof SegmentId!", generatorName));
}
-
+
@Override
public @NonNull IdGenerator getActual() {
return tryGet(true);
}
-
+
@Override
public @NonNull IdConverter idConverter() {
return getActual().idConverter();
diff --git a/cosid-core/src/main/java/me/ahoo/cosid/provider/NotFoundIdGeneratorException.java b/cosid-core/src/main/java/me/ahoo/cosid/provider/NotFoundIdGeneratorException.java
index daf823247c..96a25d770c 100644
--- a/cosid-core/src/main/java/me/ahoo/cosid/provider/NotFoundIdGeneratorException.java
+++ b/cosid-core/src/main/java/me/ahoo/cosid/provider/NotFoundIdGeneratorException.java
@@ -16,18 +16,28 @@
import me.ahoo.cosid.CosIdException;
/**
- * Not Found IdGenerator Exception.
+ * Exception thrown when an ID generator is not found.
*
* @author ahoo wang
*/
public class NotFoundIdGeneratorException extends CosIdException {
private final String generatorName;
+ /**
+ * Creates a new exception.
+ *
+ * @param generatorName the name of the generator that was not found
+ */
public NotFoundIdGeneratorException(String generatorName) {
super(String.format("IdGenerator name:[%s] not found.", generatorName));
this.generatorName = generatorName;
}
+ /**
+ * Gets the generator name that was not found.
+ *
+ * @return the generator name
+ */
public String getGeneratorName() {
return generatorName;
}
diff --git a/cosid-core/src/main/java/me/ahoo/cosid/segment/DefaultSegmentId.java b/cosid-core/src/main/java/me/ahoo/cosid/segment/DefaultSegmentId.java
index 08c1b22098..217d806c4b 100644
--- a/cosid-core/src/main/java/me/ahoo/cosid/segment/DefaultSegmentId.java
+++ b/cosid-core/src/main/java/me/ahoo/cosid/segment/DefaultSegmentId.java
@@ -25,6 +25,10 @@
/**
* Default segment algorithm ID generator.
*
+ * Provides thread-safe ID generation using a segment-based approach.
+ * Allocates ID segments from a central distributor and generates IDs
+ * locally within each segment for high throughput.
+ *
* @author ahoo wang
*/
@Slf4j
@@ -36,10 +40,21 @@ public class DefaultSegmentId implements SegmentId {
@GuardedBy("this")
private volatile IdSegment segment = DefaultIdSegment.OVERFLOW;
+ /**
+ * Creates a generator with infinite segment TTL.
+ *
+ * @param maxIdDistributor the segment distributor
+ */
public DefaultSegmentId(IdSegmentDistributor maxIdDistributor) {
this(TIME_TO_LIVE_FOREVER, maxIdDistributor);
}
+ /**
+ * Creates a generator with specified segment TTL.
+ *
+ * @param idSegmentTtl segment time-to-live in seconds
+ * @param maxIdDistributor the segment distributor
+ */
public DefaultSegmentId(long idSegmentTtl, IdSegmentDistributor maxIdDistributor) {
Preconditions.checkArgument(idSegmentTtl > 0, "idSegmentTtl:[%s] must be greater than 0.", idSegmentTtl);
diff --git a/cosid-core/src/main/java/me/ahoo/cosid/segment/IdSegmentChain.java b/cosid-core/src/main/java/me/ahoo/cosid/segment/IdSegmentChain.java
index 2ad4b03c97..9536a9e30b 100644
--- a/cosid-core/src/main/java/me/ahoo/cosid/segment/IdSegmentChain.java
+++ b/cosid-core/src/main/java/me/ahoo/cosid/segment/IdSegmentChain.java
@@ -20,43 +20,68 @@
import java.util.function.Function;
/**
- * Chained ID segment.
+ * Chained ID segment for lock-free segment chain ID generation.
+ *
+ * This class chains multiple ID segments together, allowing for seamless
+ * transition between segments without blocking. When one segment is exhausted,
+ * the next segment in the chain is used.
*
* @author ahoo wang
*/
public class IdSegmentChain implements IdSegment {
+ /**
+ * Version number for the root chain.
+ */
public static final int ROOT_VERSION = -1;
+ /**
+ * Sentinel value indicating next has not been set.
+ */
public static final IdSegmentChain NOT_SET = null;
-
+
private final long version;
private final IdSegment idSegment;
@GuardedBy("this")
private volatile IdSegmentChain next;
private final boolean allowReset;
+ /**
+ * Creates a new chain segment linked to a previous chain.
+ *
+ * @param previousChain the previous chain in the link
+ * @param idSegment the ID segment for this chain
+ * @param allowReset whether reset is allowed
+ */
public IdSegmentChain(IdSegmentChain previousChain, IdSegment idSegment, boolean allowReset) {
this(previousChain.getVersion() + 1, idSegment, allowReset);
}
-
+
+ /**
+ * Creates a new chain segment with explicit version.
+ *
+ * @param version the version number
+ * @param idSegment the ID segment for this chain
+ * @param allowReset whether reset is allowed
+ */
public IdSegmentChain(long version, IdSegment idSegment, boolean allowReset) {
this.version = version;
this.idSegment = idSegment;
this.allowReset = allowReset;
}
-
+
/**
- * try set next Chained ID segment.
+ * Attempts to set the next segment in the chain.
*
- * @param idSegmentChainSupplier {@link IdSegmentChain} supplier
- * @return true if set successfully
- * @throws NextIdSegmentExpiredException This exception is thrown
- * if the provided {@link IdSegmentChain} has expired.
+ * If next is already set, returns false without modifying.
+ *
+ * @param idSegmentChainSupplier supplier that creates the next segment based on this
+ * @return true if set successfully, false if next was already set
+ * @throws NextIdSegmentExpiredException if the provided segment has expired
*/
public boolean trySetNext(Function Holds the configuration parameters needed to allocate ID segments
+ * from a distributor (namespace, name, offset, step).
*
* @author ahoo wang
*/
@@ -24,6 +27,14 @@ public class IdSegmentDistributorDefinition {
private final long offset;
private final long step;
+ /**
+ * Creates a new definition.
+ *
+ * @param namespace the namespace
+ * @param name the segment name
+ * @param offset the starting offset
+ * @param step the step size for segment allocation
+ */
public IdSegmentDistributorDefinition(String namespace, String name, long offset, long step) {
this.namespace = namespace;
this.name = name;
@@ -31,22 +42,47 @@ public IdSegmentDistributorDefinition(String namespace, String name, long offset
this.step = step;
}
+ /**
+ * Gets the namespace.
+ *
+ * @return the namespace
+ */
public String getNamespace() {
return namespace;
}
+ /**
+ * Gets the segment name.
+ *
+ * @return the name
+ */
public String getName() {
return name;
}
+ /**
+ * Gets the full namespaced name.
+ *
+ * @return namespace.name
+ */
public String getNamespacedName() {
return IdSegmentDistributor.getNamespacedName(getNamespace(), getName());
}
+ /**
+ * Gets the starting offset.
+ *
+ * @return the offset
+ */
public long getOffset() {
return offset;
}
+ /**
+ * Gets the step size.
+ *
+ * @return the step
+ */
public long getStep() {
return step;
}
diff --git a/cosid-core/src/main/java/me/ahoo/cosid/segment/IdSegmentDistributorFactory.java b/cosid-core/src/main/java/me/ahoo/cosid/segment/IdSegmentDistributorFactory.java
index 8a5ce6f010..1c7aa0e4aa 100644
--- a/cosid-core/src/main/java/me/ahoo/cosid/segment/IdSegmentDistributorFactory.java
+++ b/cosid-core/src/main/java/me/ahoo/cosid/segment/IdSegmentDistributorFactory.java
@@ -17,12 +17,18 @@
import org.jspecify.annotations.NonNull;
/**
- * {@link IdSegmentDistributor} Factory.
+ * Factory interface for creating {@link IdSegmentDistributor} instances.
*
* @author ahoo wang
*/
@FunctionalInterface
public interface IdSegmentDistributorFactory {
+ /**
+ * Creates an ID segment distributor from a definition.
+ *
+ * @param definition the distributor definition
+ * @return the created distributor
+ */
@NonNull
IdSegmentDistributor create(IdSegmentDistributorDefinition definition);
}
diff --git a/cosid-core/src/main/java/me/ahoo/cosid/segment/MergedIdSegment.java b/cosid-core/src/main/java/me/ahoo/cosid/segment/MergedIdSegment.java
index 974d511765..bd43c977d3 100644
--- a/cosid-core/src/main/java/me/ahoo/cosid/segment/MergedIdSegment.java
+++ b/cosid-core/src/main/java/me/ahoo/cosid/segment/MergedIdSegment.java
@@ -18,35 +18,54 @@
import java.util.concurrent.TimeUnit;
/**
- * Merged IdSegment.
+ * Merged ID segment that divides a segment into multiple sub-segments.
+ *
+ * This allows a single allocated segment to be shared among multiple
+ * consumers or purposes by splitting the step into equal portions.
*
* @author ahoo wang
*/
public class MergedIdSegment implements IdSegment {
-
+
private final int segments;
private final IdSegment idSegment;
private final long singleStep;
-
+
+ /**
+ * Creates a merged segment.
+ *
+ * @param segments number of sub-segments to create
+ * @param idSegment the underlying segment
+ */
public MergedIdSegment(int segments, IdSegment idSegment) {
this.segments = segments;
this.idSegment = idSegment;
this.singleStep = idSegment.getStep() / segments;
}
-
+
@Override
public GroupedKey group() {
return idSegment.group();
}
-
+
+ /**
+ * Gets the number of sub-segments.
+ *
+ * @return number of segments
+ */
public int getSegments() {
return segments;
}
-
+
+ /**
+ * Gets the step size for each sub-segment.
+ *
+ * @return single step size
+ */
public long getSingleStep() {
return singleStep;
}
-
+
/**
* ID segment fetch time.
* unit {@link TimeUnit#MILLISECONDS}
@@ -57,37 +76,37 @@ public long getSingleStep() {
public long getFetchTime() {
return idSegment.getFetchTime();
}
-
+
@Override
public long getMaxId() {
return idSegment.getMaxId();
}
-
+
@Override
public long getOffset() {
return idSegment.getOffset();
}
-
+
@Override
public long getSequence() {
return idSegment.getSequence();
}
-
+
@Override
public long getStep() {
return idSegment.getStep();
}
-
+
@Override
public long getTtl() {
return idSegment.getTtl();
}
-
+
@Override
public long incrementAndGet() {
return idSegment.incrementAndGet();
}
-
+
@Override
public String toString() {
return "MergedIdSegment{"
diff --git a/cosid-core/src/main/java/me/ahoo/cosid/segment/NextIdSegmentExpiredException.java b/cosid-core/src/main/java/me/ahoo/cosid/segment/NextIdSegmentExpiredException.java
index 0d39aec9d0..d3b357ffd3 100644
--- a/cosid-core/src/main/java/me/ahoo/cosid/segment/NextIdSegmentExpiredException.java
+++ b/cosid-core/src/main/java/me/ahoo/cosid/segment/NextIdSegmentExpiredException.java
@@ -20,7 +20,11 @@
import java.util.concurrent.atomic.AtomicLong;
/**
- * Next IdSegment Expired Exception.
+ * Exception thrown when a next ID segment is invalid.
+ *
+ * This exception indicates that the provided next segment has an offset
+ * that is not greater than the current segment's offset, which would cause
+ * ID conflicts or duplication.
*
* @author ahoo wang
*/
@@ -29,6 +33,12 @@ public class NextIdSegmentExpiredException extends CosIdException {
private final IdSegment current;
private final IdSegment next;
+ /**
+ * Creates a new exception.
+ *
+ * @param current the current segment
+ * @param next the invalid next segment
+ */
public NextIdSegmentExpiredException(IdSegment current, IdSegment next) {
super(Strings.lenientFormat("The next IdSegment:[%s] cannot be before the current IdSegment:[%s]-- times:[%s].",
next,
@@ -39,10 +49,20 @@ public NextIdSegmentExpiredException(IdSegment current, IdSegment next) {
this.next = next;
}
+ /**
+ * Gets the current segment.
+ *
+ * @return the current segment
+ */
public IdSegment getCurrent() {
return current;
}
+ /**
+ * Gets the invalid next segment.
+ *
+ * @return the next segment
+ */
public IdSegment getNext() {
return next;
}
diff --git a/cosid-core/src/main/java/me/ahoo/cosid/segment/StringSegmentId.java b/cosid-core/src/main/java/me/ahoo/cosid/segment/StringSegmentId.java
index 175a7cef29..964c8e6619 100644
--- a/cosid-core/src/main/java/me/ahoo/cosid/segment/StringSegmentId.java
+++ b/cosid-core/src/main/java/me/ahoo/cosid/segment/StringSegmentId.java
@@ -18,18 +18,27 @@
import me.ahoo.cosid.stat.generator.IdGeneratorStat;
/**
- * String SegmentId.
+ * String-based SegmentId wrapper.
+ *
+ * Wraps a SegmentId with a string converter for generating
+ * string-based IDs while maintaining segment functionality.
*
* @author ahoo wang
*/
public class StringSegmentId extends StringIdGeneratorDecorator implements SegmentId {
private final SegmentId actualSegmentId;
-
+
+ /**
+ * Creates a new StringSegmentId.
+ *
+ * @param actual the underlying segment ID
+ * @param idConverter the converter for string generation
+ */
public StringSegmentId(SegmentId actual, IdConverter idConverter) {
super(actual, idConverter);
this.actualSegmentId = actual;
}
-
+
@Override
public IdSegment current() {
return actualSegmentId.current();
diff --git a/cosid-core/src/main/java/me/ahoo/cosid/segment/concurrent/AffinityJob.java b/cosid-core/src/main/java/me/ahoo/cosid/segment/concurrent/AffinityJob.java
index c26593df92..f3e4992808 100644
--- a/cosid-core/src/main/java/me/ahoo/cosid/segment/concurrent/AffinityJob.java
+++ b/cosid-core/src/main/java/me/ahoo/cosid/segment/concurrent/AffinityJob.java
@@ -16,32 +16,58 @@
import me.ahoo.cosid.util.Clock;
/**
- * Affinity Job.
+ * Job with affinity for prefetch worker assignment.
+ *
+ * Represents a segment prefetch task that has affinity to a specific
+ * worker instance for consistent segment allocation.
*
* @author ahoo wang
*/
public interface AffinityJob extends Runnable {
-
+
+ /**
+ * Gets the unique job identifier.
+ *
+ * @return the job ID
+ */
String getJobId();
-
+
+ /**
+ * Gets the affinity key for worker assignment.
+ *
+ * @return the affinity key (defaults to job ID)
+ */
default String affinity() {
return getJobId();
}
-
+
+ /**
+ * Signals this job is hungry and needs prefetch.
+ */
default void hungry() {
setHungerTime(Clock.CACHE.secondTime());
getPrefetchWorker().wakeup(this);
}
-
+
/**
- * set hunger time.
+ * Sets the hunger time for this job.
*
- * @param hungerTime {@link java.util.concurrent.TimeUnit#SECONDS}
+ * @param hungerTime time in seconds since epoch
*/
void setHungerTime(long hungerTime);
-
+
+ /**
+ * Gets the prefetch worker for this job.
+ *
+ * @return the prefetch worker
+ */
PrefetchWorker getPrefetchWorker();
-
+
+ /**
+ * Sets the prefetch worker for this job.
+ *
+ * @param prefetchWorker the worker to set
+ */
void setPrefetchWorker(PrefetchWorker prefetchWorker);
-
+
}
diff --git a/cosid-core/src/main/java/me/ahoo/cosid/segment/concurrent/DefaultPrefetchWorker.java b/cosid-core/src/main/java/me/ahoo/cosid/segment/concurrent/DefaultPrefetchWorker.java
index af108f22ac..ec29b9764a 100644
--- a/cosid-core/src/main/java/me/ahoo/cosid/segment/concurrent/DefaultPrefetchWorker.java
+++ b/cosid-core/src/main/java/me/ahoo/cosid/segment/concurrent/DefaultPrefetchWorker.java
@@ -22,7 +22,10 @@
import java.util.concurrent.locks.LockSupport;
/**
- * Default Prefetch Worker.
+ * Default prefetch worker implementation.
+ *
+ * Runs a background thread that periodically executes affinity jobs
+ * to prefetch ID segments before they are exhausted.
*
* @author ahoo wang
*/
@@ -34,6 +37,11 @@ public class DefaultPrefetchWorker extends Thread implements PrefetchWorker {
private final Duration prefetchPeriod;
private final CopyOnWriteArraySet Manages background prefetching of ID segments to ensure
+ * segments are available before they are exhausted.
*
* @author ahoo wang
*/
@ThreadSafe
public interface PrefetchWorker {
+ /**
+ * Gets the worker name.
+ *
+ * @return the worker name
+ */
String getName();
+ /**
+ * Submits a job for prefetching.
+ *
+ * @param affinityJob the job to submit
+ */
void submit(AffinityJob affinityJob);
+ /**
+ * Cancels a prefetch job.
+ *
+ * @param affinityJob the job to cancel
+ */
void cancel(AffinityJob affinityJob);
+ /**
+ * Wakes up a job for immediate processing.
+ *
+ * @param affinityJob the job to wake up
+ */
void wakeup(AffinityJob affinityJob);
+ /**
+ * Shuts down the worker.
+ */
void shutdown();
}
diff --git a/cosid-core/src/main/java/me/ahoo/cosid/segment/grouped/DefaultGroupedIdSegmentDistributor.java b/cosid-core/src/main/java/me/ahoo/cosid/segment/grouped/DefaultGroupedIdSegmentDistributor.java
index f7a05f9c75..13cc6de6a9 100644
--- a/cosid-core/src/main/java/me/ahoo/cosid/segment/grouped/DefaultGroupedIdSegmentDistributor.java
+++ b/cosid-core/src/main/java/me/ahoo/cosid/segment/grouped/DefaultGroupedIdSegmentDistributor.java
@@ -21,19 +21,34 @@
import org.jspecify.annotations.NonNull;
+/**
+ * Default grouped ID segment distributor implementation.
+ *
+ * Manages segment distribution with group-based isolation,
+ * creating separate distributors for each group.
+ *
+ * @author ahoo wang
+ */
public class DefaultGroupedIdSegmentDistributor implements GroupedIdSegmentDistributor {
private final GroupBySupplier groupBySupplier;
private final IdSegmentDistributorDefinition idSegmentDistributorDefinition;
private final IdSegmentDistributorFactory idSegmentDistributorFactory;
private volatile GroupedBinding currentGroup;
-
+
+ /**
+ * Creates a grouped distributor.
+ *
+ * @param groupBySupplier the group supplier
+ * @param idSegmentDistributorDefinition the definition
+ * @param idSegmentDistributorFactory the factory
+ */
public DefaultGroupedIdSegmentDistributor(GroupBySupplier groupBySupplier, IdSegmentDistributorDefinition idSegmentDistributorDefinition, IdSegmentDistributorFactory idSegmentDistributorFactory) {
this.groupBySupplier = groupBySupplier;
this.idSegmentDistributorDefinition = idSegmentDistributorDefinition;
this.idSegmentDistributorFactory = idSegmentDistributorFactory;
this.ensureGroupedBinding();
}
-
+
private GroupedBinding ensureGroupedBinding() {
GroupedKey groupedKey = groupBySupplier.get();
if (currentGroup != null && currentGroup.group().equals(groupedKey)) {
@@ -50,121 +65,135 @@ private GroupedBinding ensureGroupedBinding() {
idSegmentDistributorDefinition.getStep());
this.currentGroup = new GroupedBinding(groupedKey, idSegmentDistributorFactory.create(groupedDef));
}
-
+
return currentGroup;
}
-
+
+ /**
+ * Gets the group supplier.
+ *
+ * @return the supplier
+ */
public GroupBySupplier groupBySupplier() {
return groupBySupplier;
}
-
+
@Override
public @NonNull String getNamespace() {
return this.idSegmentDistributorDefinition.getNamespace();
}
-
+
@Override
public @NonNull String getName() {
return this.idSegmentDistributorDefinition.getName();
}
-
+
@Override
public long getStep() {
return this.idSegmentDistributorDefinition.getStep();
}
-
+
@Override
public GroupedKey group() {
return this.ensureGroupedBinding().group();
}
-
+
@Override
public long nextMaxId() {
return this.ensureGroupedBinding().nextMaxId();
}
-
+
@Override
public long nextMaxId(long step) {
return this.ensureGroupedBinding().nextMaxId(step);
}
-
+
@Override
public @NonNull IdSegment nextIdSegment() {
return this.ensureGroupedBinding().nextIdSegment();
}
-
+
@Override
public @NonNull IdSegment nextIdSegment(long ttl) {
return this.ensureGroupedBinding().nextIdSegment(ttl);
}
-
+
@Override
public @NonNull IdSegment nextIdSegment(int segments, long ttl) {
return this.ensureGroupedBinding().nextIdSegment(segments, ttl);
}
-
+
@Override
public @NonNull IdSegmentChain nextIdSegmentChain(IdSegmentChain previousChain, int segments, long ttl) {
return this.ensureGroupedBinding().nextIdSegmentChain(previousChain, segments, ttl);
}
-
+
@Override
public @NonNull IdSegmentChain nextIdSegmentChain(IdSegmentChain previousChain) {
return this.ensureGroupedBinding().nextIdSegmentChain(previousChain);
}
-
+
+ /**
+ * Holds a group binding with its distributor.
+ */
public static class GroupedBinding implements GroupedIdSegmentDistributor {
-
+
private final GroupedKey group;
private final IdSegmentDistributor idSegmentDistributor;
-
+
+ /**
+ * Creates a binding.
+ *
+ * @param group the group key
+ * @param idSegmentDistributor the distributor
+ */
public GroupedBinding(GroupedKey group, IdSegmentDistributor idSegmentDistributor) {
this.group = group;
this.idSegmentDistributor = idSegmentDistributor;
}
-
+
@Override
public GroupedKey group() {
return group;
}
-
+
@Override
public @NonNull String getNamespace() {
return idSegmentDistributor.getNamespace();
}
-
+
@Override
public @NonNull String getName() {
return idSegmentDistributor.getName();
}
-
+
@Override
public long getStep() {
return idSegmentDistributor.getStep();
}
-
+
@Override
public long nextMaxId(long step) {
return idSegmentDistributor.nextMaxId(step);
}
-
+
private long getMinTtl(long ttl) {
long groupedTtl = group.ttl();
return Math.min(groupedTtl, ttl);
}
-
+
@Override
public @NonNull IdSegment nextIdSegment(long ttl) {
long minTtl = getMinTtl(ttl);
return GroupedIdSegmentDistributor.super.nextIdSegment(minTtl);
}
-
+
@Override
public @NonNull IdSegment nextIdSegment(int segments, long ttl) {
long minTtl = getMinTtl(ttl);
return GroupedIdSegmentDistributor.super.nextIdSegment(segments, minTtl);
}
-
+
@Override
public @NonNull IdSegmentChain nextIdSegmentChain(IdSegmentChain previousChain, int segments, long ttl) {
long minTtl = getMinTtl(ttl);
diff --git a/cosid-core/src/main/java/me/ahoo/cosid/segment/grouped/GroupBySupplier.java b/cosid-core/src/main/java/me/ahoo/cosid/segment/grouped/GroupBySupplier.java
index 38e3fa7d2b..fab2be8dca 100644
--- a/cosid-core/src/main/java/me/ahoo/cosid/segment/grouped/GroupBySupplier.java
+++ b/cosid-core/src/main/java/me/ahoo/cosid/segment/grouped/GroupBySupplier.java
@@ -15,6 +15,9 @@
import java.util.function.Supplier;
+/**
+ * Supplier of {@link GroupedKey} for grouping related ID segments.
+ */
public interface GroupBySupplier extends Supplier Implementations return a {@link GroupedKey} that represents the sharding
+ * key for this object. This is used by segmented ID generators to organize
+ * IDs into logical groups.
+ */
public interface Grouped {
+ /**
+ * Gets the grouping key for this object.
+ *
+ * Default implementation returns {@link GroupedKey#NEVER}, indicating
+ * this object should not be grouped.
+ *
+ * @return the grouping key
+ */
default GroupedKey group() {
return GroupedKey.NEVER;
}
diff --git a/cosid-core/src/main/java/me/ahoo/cosid/segment/grouped/GroupedAccessor.java b/cosid-core/src/main/java/me/ahoo/cosid/segment/grouped/GroupedAccessor.java
index e629d5e7a8..3ea78cb339 100644
--- a/cosid-core/src/main/java/me/ahoo/cosid/segment/grouped/GroupedAccessor.java
+++ b/cosid-core/src/main/java/me/ahoo/cosid/segment/grouped/GroupedAccessor.java
@@ -18,14 +18,32 @@
import java.util.Objects;
+/**
+ * Thread-local accessor for managing grouped key context.
+ *
+ * Provides thread-local storage for the current group key,
+ * allowing different threads to work with different group contexts.
+ *
+ * @author ahoo wang
+ */
@ThreadSafe
public final class GroupedAccessor {
private static final ThreadLocal Grouped distributors allow ID segments to be partitioned by a grouping key
+ * (e.g., time-based buckets like "2024-01" for monthly sharding).
+ *
+ * @author ahoo wang
+ */
public interface GroupedIdSegmentDistributor extends IdSegmentDistributor {
-
+
@Override
default boolean allowReset() {
return true;
diff --git a/cosid-core/src/main/java/me/ahoo/cosid/segment/grouped/GroupedIdSegmentDistributorFactory.java b/cosid-core/src/main/java/me/ahoo/cosid/segment/grouped/GroupedIdSegmentDistributorFactory.java
index 69b5def5ba..3d04c5fcb0 100644
--- a/cosid-core/src/main/java/me/ahoo/cosid/segment/grouped/GroupedIdSegmentDistributorFactory.java
+++ b/cosid-core/src/main/java/me/ahoo/cosid/segment/grouped/GroupedIdSegmentDistributorFactory.java
@@ -19,15 +19,28 @@
import org.jspecify.annotations.NonNull;
+/**
+ * Factory for creating grouped ID segment distributors.
+ *
+ * Wraps an existing factory with grouping support.
+ *
+ * @author ahoo wang
+ */
public class GroupedIdSegmentDistributorFactory implements IdSegmentDistributorFactory {
private final GroupBySupplier groupBySupplier;
private final IdSegmentDistributorFactory actual;
-
+
+ /**
+ * Creates a factory with grouping support.
+ *
+ * @param groupBySupplier the group supplier
+ * @param actual the underlying factory
+ */
public GroupedIdSegmentDistributorFactory(GroupBySupplier groupBySupplier, IdSegmentDistributorFactory actual) {
this.groupBySupplier = groupBySupplier;
this.actual = actual;
}
-
+
@Override
public @NonNull IdSegmentDistributor create(IdSegmentDistributorDefinition definition) {
return new DefaultGroupedIdSegmentDistributor(groupBySupplier, definition, actual);
diff --git a/cosid-core/src/main/java/me/ahoo/cosid/segment/grouped/GroupedKey.java b/cosid-core/src/main/java/me/ahoo/cosid/segment/grouped/GroupedKey.java
index 269f7abc23..d6b62e40c0 100644
--- a/cosid-core/src/main/java/me/ahoo/cosid/segment/grouped/GroupedKey.java
+++ b/cosid-core/src/main/java/me/ahoo/cosid/segment/grouped/GroupedKey.java
@@ -20,34 +20,61 @@
import java.util.Objects;
+/**
+ * Key used for grouping/sharding of ID segments.
+ *
+ * Represents a logical grouping key with an optional TTL for time-based
+ * sharding strategies (e.g., daily or monthly buckets).
+ *
+ * @author ahoo wang
+ */
public final class GroupedKey {
+ /**
+ * Sentinel value indicating no grouping.
+ */
public static final GroupedKey NEVER = new GroupedKey("", IdSegment.TIME_TO_LIVE_FOREVER);
private final String key;
private final long ttlAt;
-
+
+ /**
+ * Creates a new GroupedKey.
+ *
+ * @param key the grouping key (e.g., "2024-01" for monthly)
+ * @param ttlAt the time-to-live expiration timestamp in seconds
+ */
public GroupedKey(String key, long ttlAt) {
this.key = key;
this.ttlAt = ttlAt;
}
-
+
+ /**
+ * Gets the grouping key.
+ *
+ * @return the key
+ */
public String getKey() {
return key;
}
-
+
/**
- * get ttlAt of group.
+ * Gets the TTL expiration timestamp.
*
- * @return ttlAt
+ * @return TTL timestamp in seconds
* @see IdSegment#getTtl()
*/
public long getTtlAt() {
return ttlAt;
}
-
+
+ /**
+ * Calculates remaining TTL from current time.
+ *
+ * @return remaining TTL in seconds, or 0 if expired
+ */
public long ttl() {
return ttlAt - Clock.CACHE.secondTime();
}
-
+
@Override
public boolean equals(Object o) {
if (this == o) {
@@ -59,12 +86,12 @@ public boolean equals(Object o) {
GroupedKey that = (GroupedKey) o;
return ttlAt == that.ttlAt && Objects.equals(key, that.key);
}
-
+
@Override
public int hashCode() {
return Objects.hash(key, ttlAt);
}
-
+
@Override
public String toString() {
return MoreObjects.toStringHelper(this)
@@ -72,7 +99,13 @@ public String toString() {
.add("ttlAt", ttlAt)
.toString();
}
-
+
+ /**
+ * Creates a GroupedKey that never expires.
+ *
+ * @param key the grouping key
+ * @return a forever GroupedKey
+ */
public static GroupedKey forever(String key) {
return new GroupedKey(key, IdSegment.TIME_TO_LIVE_FOREVER);
}
diff --git a/cosid-core/src/main/java/me/ahoo/cosid/segment/grouped/date/AbstractDateGroupBySupplier.java b/cosid-core/src/main/java/me/ahoo/cosid/segment/grouped/date/AbstractDateGroupBySupplier.java
index fa196f6a9a..238113c77a 100644
--- a/cosid-core/src/main/java/me/ahoo/cosid/segment/grouped/date/AbstractDateGroupBySupplier.java
+++ b/cosid-core/src/main/java/me/ahoo/cosid/segment/grouped/date/AbstractDateGroupBySupplier.java
@@ -21,15 +21,37 @@
import java.time.format.DateTimeFormatter;
import java.time.temporal.TemporalAccessor;
+/**
+ * Abstract base class for date-based group key suppliers.
+ *
+ * @param Caches range sharding results to reduce computation overhead
+ * for frequently accessed ranges.
+ *
+ * @param Used by Interval and Mod algorithms where the number of
+ * nodes is known in advance, avoiding the memory overhead
+ * of HashSet and unnecessary array expansion.
*
* @author ahoo wang
*/
diff --git a/cosid-core/src/main/java/me/ahoo/cosid/sharding/IntervalStep.java b/cosid-core/src/main/java/me/ahoo/cosid/sharding/IntervalStep.java
index 088e0f7af2..f8b3cfe5ce 100644
--- a/cosid-core/src/main/java/me/ahoo/cosid/sharding/IntervalStep.java
+++ b/cosid-core/src/main/java/me/ahoo/cosid/sharding/IntervalStep.java
@@ -19,39 +19,67 @@
import java.time.temporal.ChronoUnit;
/**
- * Interval Step.
+ * Represents a time interval step for sharding operations.
+ *
+ * Defines the granularity and size of time-based sharding intervals.
+ * Used for interval sharding algorithms in ShardingSphere integration.
*
* @author ahoo wang
*/
@Immutable
public class IntervalStep {
+ /**
+ * Default amount of 1.
+ */
public static final int DEFAULT_AMOUNT = 1;
-
+
private final ChronoUnit unit;
private final int amount;
-
+
+ /**
+ * Creates an interval step.
+ *
+ * @param unit the time unit (years, months, days, etc.)
+ * @param amount the number of units per step
+ */
public IntervalStep(ChronoUnit unit, int amount) {
this.unit = unit;
this.amount = amount;
}
-
+
+ /**
+ * Gets the time unit.
+ *
+ * @return the unit
+ */
public ChronoUnit getUnit() {
return unit;
}
-
+
+ /**
+ * Gets the amount.
+ *
+ * @return the amount
+ */
public int getAmount() {
return amount;
}
-
+
+ /**
+ * Calculates the next time by adding the interval.
+ *
+ * @param previous the previous time
+ * @return the next time
+ */
public LocalDateTime next(LocalDateTime previous) {
return previous.plus(amount, unit);
}
-
+
/**
- * 按照 {@link #unit} 保留单位时间精度.
+ * Truncates time to the precision of the unit.
*
- * @param time time
- * @return Unit precision LocalDateTime
+ * @param time the time to truncate
+ * @return time truncated to unit precision
*/
public LocalDateTime floorUnit(LocalDateTime time) {
switch (unit) {
@@ -77,23 +105,35 @@ public LocalDateTime floorUnit(LocalDateTime time) {
throw new IllegalStateException("Unexpected value: " + unit);
}
}
-
+
/**
- * 计算单位偏移量.
- * Start with 0
+ * Calculates the offset from start to time in unit increments.
*
- * @param start 最小值
- * @param time time
- * @return offset
+ * @param start the start time
+ * @param time the target time
+ * @return the offset in units
*/
public int offsetUnit(LocalDateTime start, LocalDateTime time) {
return (int) (start.until(time, unit) / amount);
}
-
+
+ /**
+ * Creates an interval step with default amount of 1.
+ *
+ * @param unit the time unit
+ * @return the interval step
+ */
public static IntervalStep of(ChronoUnit unit) {
return new IntervalStep(unit, DEFAULT_AMOUNT);
}
-
+
+ /**
+ * Creates an interval step with custom amount.
+ *
+ * @param unit the time unit
+ * @param amount the number of units
+ * @return the interval step
+ */
public static IntervalStep of(ChronoUnit unit, int amount) {
return new IntervalStep(unit, amount);
}
diff --git a/cosid-core/src/main/java/me/ahoo/cosid/sharding/IntervalTimeline.java b/cosid-core/src/main/java/me/ahoo/cosid/sharding/IntervalTimeline.java
index 409ca1f626..97d8d8f6ac 100644
--- a/cosid-core/src/main/java/me/ahoo/cosid/sharding/IntervalTimeline.java
+++ b/cosid-core/src/main/java/me/ahoo/cosid/sharding/IntervalTimeline.java
@@ -26,7 +26,11 @@
import java.util.List;
/**
- * Interval Timeline.
+ * Timeline-based interval sharding algorithm.
+ *
+ * Distributes IDs across time-based intervals, where each interval
+ * maps to a specific node. The intervals are calculated based on a
+ * configured step size (e.g., daily, monthly).
*
* Distributes IDs across nodes using modulo arithmetic.
+ * Maps a sharding value to a node by computing: {@code value % divisor}.
*
* Determines which node(s) should handle a range of ID values.
+ *
+ * @param Combines both precise sharding (single key) and range sharding (key range)
+ * capabilities to determine which node(s) should handle a given ID or ID range.
*
* This abstract class provides the base implementation for Snowflake ID generation,
+ * handling the common logic for timestamp management, sequence counting, and ID assembly.
+ * Subclasses implement {@link #getCurrentTime()} to provide time in different units
+ * (milliseconds, seconds, etc.).
+ *
+ * The ID is composed of: timestamp (configurable bits) + machine ID (configurable bits) + sequence (configurable bits)
*
* @author ahoo wang
*/
public abstract class AbstractSnowflakeId implements SnowflakeId {
+ /**
+ * Epoch timestamp used as the base for time calculations.
+ */
protected final long epoch;
+ /**
+ * Number of bits allocated for the timestamp portion.
+ */
protected final int timestampBit;
+ /**
+ * Number of bits allocated for the machine ID portion.
+ */
protected final int machineBit;
+ /**
+ * Number of bits allocated for the sequence portion.
+ */
protected final int sequenceBit;
+ /**
+ * Maximum timestamp value representable by the timestamp bits.
+ */
protected final long maxTimestamp;
+ /**
+ * Maximum sequence value representable by the sequence bits.
+ */
protected final long maxSequence;
+ /**
+ * Maximum machine ID value representable by the machine ID bits.
+ */
protected final int maxMachineId;
+ /**
+ * Number of bits to shift machine ID left (equal to sequenceBit).
+ */
protected final long machineLeft;
+ /**
+ * Number of bits to shift timestamp left (equal to sequenceBit + machineBit).
+ */
protected final long timestampLeft;
/**
- * WARN:machineLeft greater than 30 will cause overflow, so machineId should be long when calculating.
+ * The machine ID value for this instance.
+ *
+ * @implNote When machineLeft is greater than 30, overflow can occur during calculation,
+ * so machineId should be kept as long during arithmetic operations.
*/
protected final long machineId;
+ /**
+ * Threshold for resetting sequence counter when timestamp advances.
+ */
private final long sequenceResetThreshold;
+ /**
+ * Current sequence counter value.
+ */
protected long sequence = 0L;
+ /**
+ * Timestamp of the last generated ID.
+ */
protected long lastTimestamp = -1L;
+ /**
+ * Creates a new AbstractSnowflakeId.
+ *
+ * @param epoch epoch timestamp in milliseconds
+ * @param timestampBit number of bits for timestamp
+ * @param machineBit number of bits for machine ID
+ * @param sequenceBit number of bits for sequence
+ * @param machineId the machine ID value
+ * @param sequenceResetThreshold threshold for resetting sequence on timestamp advance
+ * @throws IllegalArgumentException if total bits exceed 63 or machineId is invalid
+ */
public AbstractSnowflakeId(long epoch,
int timestampBit,
int machineBit,
@@ -69,6 +126,11 @@ public AbstractSnowflakeId(long epoch,
this.sequenceResetThreshold = sequenceResetThreshold;
}
+ /**
+ * Waits until the current time is greater than the last timestamp.
+ *
+ * @return the next valid timestamp
+ */
protected long nextTime() {
long time = getCurrentTime();
while (time <= lastTimestamp) {
@@ -78,12 +140,21 @@ protected long nextTime() {
}
/**
- * get current timestamp.
+ * Gets the current time in the appropriate unit for this snowflake ID variant.
*
- * @return current timestamp
+ * @return current time value
*/
protected abstract long getCurrentTime();
+ /**
+ * Generates the next unique ID.
+ *
+ * This method is synchronized to ensure thread-safe ID generation.
+ *
+ * @return a unique snowflake ID
+ * @throws ClockBackwardsException if system clock has moved backwards
+ * @throws TimestampOverflowException if timestamp exceeds maximum value
+ */
@Override
public synchronized long generate() {
long currentTimestamp = getCurrentTime();
diff --git a/cosid-core/src/main/java/me/ahoo/cosid/snowflake/DefaultSnowflakeFriendlyId.java b/cosid-core/src/main/java/me/ahoo/cosid/snowflake/DefaultSnowflakeFriendlyId.java
index 61d6191440..d913cee126 100644
--- a/cosid-core/src/main/java/me/ahoo/cosid/snowflake/DefaultSnowflakeFriendlyId.java
+++ b/cosid-core/src/main/java/me/ahoo/cosid/snowflake/DefaultSnowflakeFriendlyId.java
@@ -21,7 +21,10 @@
import java.time.ZoneId;
/**
- * Default Snowflake FriendlyId.
+ * Default implementation of {@link SnowflakeFriendlyId}.
+ *
+ * Wraps a {@link SnowflakeId} and provides human-readable
+ * string conversion using a {@link SnowflakeIdStateParser}.
*
* @author ahoo wang
*/
@@ -29,18 +32,42 @@ public class DefaultSnowflakeFriendlyId extends StringSnowflakeId implements Sno
private final SnowflakeIdStateParser snowflakeIdStateParser;
+ /**
+ * Creates an instance with system default zone.
+ *
+ * @param actual the underlying Snowflake ID
+ */
public DefaultSnowflakeFriendlyId(SnowflakeId actual) {
this(actual, ZoneId.systemDefault());
}
+ /**
+ * Creates an instance with specified zone.
+ *
+ * @param actual the underlying Snowflake ID
+ * @param zoneId the time zone
+ */
public DefaultSnowflakeFriendlyId(SnowflakeId actual, ZoneId zoneId) {
this(actual, SnowflakeIdStateParser.of(actual, zoneId, false));
}
+ /**
+ * Creates an instance with specified parser.
+ *
+ * @param actual the underlying Snowflake ID
+ * @param snowflakeIdStateParser the state parser
+ */
public DefaultSnowflakeFriendlyId(SnowflakeId actual, SnowflakeIdStateParser snowflakeIdStateParser) {
this(actual, new SnowflakeFriendlyIdConverter(snowflakeIdStateParser), snowflakeIdStateParser);
}
+ /**
+ * Creates an instance with specified converter and parser.
+ *
+ * @param actual the underlying Snowflake ID
+ * @param converter the ID converter
+ * @param snowflakeIdStateParser the state parser
+ */
public DefaultSnowflakeFriendlyId(SnowflakeId actual, IdConverter converter, SnowflakeIdStateParser snowflakeIdStateParser) {
super(actual, converter);
this.snowflakeIdStateParser = snowflakeIdStateParser;
diff --git a/cosid-core/src/main/java/me/ahoo/cosid/snowflake/MillisecondSnowflakeIdStateParser.java b/cosid-core/src/main/java/me/ahoo/cosid/snowflake/MillisecondSnowflakeIdStateParser.java
index f00d849e1d..a5e08a8984 100644
--- a/cosid-core/src/main/java/me/ahoo/cosid/snowflake/MillisecondSnowflakeIdStateParser.java
+++ b/cosid-core/src/main/java/me/ahoo/cosid/snowflake/MillisecondSnowflakeIdStateParser.java
@@ -31,12 +31,18 @@
import java.time.format.DateTimeFormatterBuilder;
/**
- * Millisecond SnowflakeId State Parser.
+ * Parser for millisecond-based SnowflakeId state.
+ *
+ * Handles conversion between millisecond SnowflakeIds and their string
+ * representations using format: {@code yyyyMMddHHmmssSSS-machineId-sequence}.
*
* @author ahoo wang
*/
public class MillisecondSnowflakeIdStateParser extends SnowflakeIdStateParser {
+ /**
+ * Default parser instance with CosId epoch.
+ */
public static final SnowflakeIdStateParser INSTANCE = new MillisecondSnowflakeIdStateParser(
CosId.COSID_EPOCH,
MillisecondSnowflakeId.DEFAULT_TIMESTAMP_BIT,
@@ -44,6 +50,9 @@ public class MillisecondSnowflakeIdStateParser extends SnowflakeIdStateParser {
MillisecondSnowflakeId.DEFAULT_SEQUENCE_BIT
);
+ /**
+ * DateTimeFormatter for timestamps: {@code yyyyMMddHHmmssSSS}.
+ */
public static final DateTimeFormatter DATE_TIME_FORMATTER = new DateTimeFormatterBuilder()
.appendValue(YEAR, 4)
.appendValue(MONTH_OF_YEAR, 2)
@@ -54,10 +63,28 @@ public class MillisecondSnowflakeIdStateParser extends SnowflakeIdStateParser {
.appendValue(MILLI_OF_SECOND, 3)
.toFormatter();
+ /**
+ * Creates a parser with default zone and no padding.
+ *
+ * @param epoch epoch timestamp
+ * @param timestampBit bits for timestamp
+ * @param machineBit bits for machine ID
+ * @param sequenceBit bits for sequence
+ */
public MillisecondSnowflakeIdStateParser(long epoch, int timestampBit, int machineBit, int sequenceBit) {
this(epoch, timestampBit, machineBit, sequenceBit, ZoneId.systemDefault(), false);
}
+ /**
+ * Creates a parser with custom zone and padding.
+ *
+ * @param epoch epoch timestamp
+ * @param timestampBit bits for timestamp
+ * @param machineBit bits for machine ID
+ * @param sequenceBit bits for sequence
+ * @param zoneId time zone
+ * @param padStart whether to pad
+ */
public MillisecondSnowflakeIdStateParser(long epoch, int timestampBit, int machineBit, int sequenceBit, ZoneId zoneId, boolean padStart) {
super(epoch, timestampBit, machineBit, sequenceBit, zoneId, padStart);
}
diff --git a/cosid-core/src/main/java/me/ahoo/cosid/snowflake/SafeJavaScriptSnowflakeId.java b/cosid-core/src/main/java/me/ahoo/cosid/snowflake/SafeJavaScriptSnowflakeId.java
index be43373861..d20c625dc7 100644
--- a/cosid-core/src/main/java/me/ahoo/cosid/snowflake/SafeJavaScriptSnowflakeId.java
+++ b/cosid-core/src/main/java/me/ahoo/cosid/snowflake/SafeJavaScriptSnowflakeId.java
@@ -16,32 +16,63 @@
import me.ahoo.cosid.CosId;
/**
- * Safe JavaScript Number ID.
- * Number.MAX_SAFE_INTEGER = 9007199254740991
- * Math.log2(Number.MAX_SAFE_INTEGER) = 53
+ * Safe JavaScript Snowflake ID generators.
+ *
+ * JavaScript Numbers can only safely represent integers up to 2^53 - 1
+ * (Number.MAX_SAFE_INTEGER = 9007199254740991). This class provides factory
+ * methods for creating SnowflakeId instances that stay within this limit
+ * by reducing total bits to 53 or fewer.
*
* @author ahoo wang
**/
public final class SafeJavaScriptSnowflakeId {
-
+
+ /**
+ * Maximum safe JavaScript number bit count.
+ */
public static final int JAVA_SCRIPT_MAX_SAFE_NUMBER_BIT = 53;
+ /**
+ * Maximum safe JavaScript number value.
+ */
public static final long JAVA_SCRIPT_MAX_SAFE_NUMBER = 9007199254740991L;
-
+
+ /**
+ * Checks if an ID is safe for JavaScript.
+ *
+ * @param id the ID to check
+ * @return true if less than MAX_SAFE_NUMBER
+ */
public static boolean isSafeJavaScript(long id) {
return id < JAVA_SCRIPT_MAX_SAFE_NUMBER;
}
-
+
+ /**
+ * Creates a safe millisecond SnowflakeId.
+ *
+ * @param epoch epoch timestamp
+ * @param timestampBit bits for timestamp
+ * @param machineBit bits for machine ID
+ * @param sequenceBit bits for sequence
+ * @param machineId the machine ID
+ * @param sequenceResetThreshold threshold for sequence reset
+ * @return a new MillisecondSnowflakeId
+ */
public static MillisecondSnowflakeId ofMillisecond(long epoch, int timestampBit, int machineBit, int sequenceBit, int machineId, long sequenceResetThreshold) {
checkTotalBit(timestampBit, machineBit, sequenceBit);
return new MillisecondSnowflakeId(epoch, timestampBit, machineBit, sequenceBit, machineId, sequenceResetThreshold);
}
-
+
/**
- * Max Sequence (9 bits) = ((1<<)*1000) = 512000 (TPS)
- * Max Machine (3 bits) = 1<<3 = 8
- * Max Timestamp = 2199023255551 ms ~~ 69.7 years
+ * Creates a safe millisecond SnowflakeId with default safe configuration.
*
- * @param machineId 服务实例编号
+ * Default safe configuration:
+ * Default safe configuration:
+ * Similar to {@link MillisecondSnowflakeId} but uses seconds instead of milliseconds
+ * as the time unit. This allows for a longer timestamp range but with lower
+ * time precision.
+ *
+ * Default configuration:
+ * Handles conversion between second SnowflakeIds and their string
+ * representations using format: {@code yyyyMMddHHmmss-machineId-sequence}.
*
* @author ahoo wang
*/
public class SecondSnowflakeIdStateParser extends SnowflakeIdStateParser {
+ /**
+ * DateTimeFormatter for timestamps: {@code yyyyMMddHHmmss}.
+ */
public static final DateTimeFormatter DATE_TIME_FORMATTER = new DateTimeFormatterBuilder()
.appendValue(YEAR, 4)
.appendValue(MONTH_OF_YEAR, 2)
@@ -43,10 +49,28 @@ public class SecondSnowflakeIdStateParser extends SnowflakeIdStateParser {
.appendValue(SECOND_OF_MINUTE, 2)
.toFormatter();
+ /**
+ * Creates a parser with default zone and no padding.
+ *
+ * @param epoch epoch timestamp
+ * @param timestampBit bits for timestamp
+ * @param machineBit bits for machine ID
+ * @param sequenceBit bits for sequence
+ */
public SecondSnowflakeIdStateParser(long epoch, int timestampBit, int machineBit, int sequenceBit) {
this(epoch, timestampBit, machineBit, sequenceBit, ZoneId.systemDefault(), false);
}
+ /**
+ * Creates a parser with custom zone and padding.
+ *
+ * @param epoch epoch timestamp
+ * @param timestampBit bits for timestamp
+ * @param machineBit bits for machine ID
+ * @param sequenceBit bits for sequence
+ * @param zoneId time zone
+ * @param padStart whether to pad
+ */
public SecondSnowflakeIdStateParser(long epoch, int timestampBit, int machineBit, int sequenceBit, ZoneId zoneId, boolean padStart) {
super(epoch, timestampBit, machineBit, sequenceBit, zoneId, padStart);
}
diff --git a/cosid-core/src/main/java/me/ahoo/cosid/snowflake/SnowflakeFriendlyId.java b/cosid-core/src/main/java/me/ahoo/cosid/snowflake/SnowflakeFriendlyId.java
index 5bf2fcbbda..cebfcb99a3 100644
--- a/cosid-core/src/main/java/me/ahoo/cosid/snowflake/SnowflakeFriendlyId.java
+++ b/cosid-core/src/main/java/me/ahoo/cosid/snowflake/SnowflakeFriendlyId.java
@@ -16,29 +16,54 @@
import org.jspecify.annotations.NonNull;
/**
- * Snowflake FriendlyId.
+ * Snowflake ID with human-readable string representation.
+ *
+ * Provides methods to convert Snowflake IDs to and from
+ * a friendly string format containing timestamp, machine ID, and sequence.
*
* @author ahoo wang
*/
public interface SnowflakeFriendlyId extends SnowflakeId {
-
+
+ /**
+ * Gets the state parser.
+ *
+ * @return the parser
+ */
@NonNull
SnowflakeIdStateParser getParser();
-
+
+ /**
+ * Parses a raw ID to friendly state.
+ *
+ * @param id the raw ID
+ * @return the friendly state
+ */
@NonNull
default SnowflakeIdState friendlyId(long id) {
return getParser().parse(id);
}
-
+
+ /**
+ * Generates an ID and returns its friendly state.
+ *
+ * @return the friendly state
+ */
@NonNull
default SnowflakeIdState friendlyId() {
long id = generate();
return friendlyId(id);
}
-
+
+ /**
+ * Parses a friendly ID string to state.
+ *
+ * @param friendlyId the friendly ID string
+ * @return the friendly state
+ */
@NonNull
default SnowflakeIdState ofFriendlyId(String friendlyId) {
return getParser().parse(friendlyId);
}
-
+
}
diff --git a/cosid-core/src/main/java/me/ahoo/cosid/snowflake/SnowflakeIdState.java b/cosid-core/src/main/java/me/ahoo/cosid/snowflake/SnowflakeIdState.java
index db96a4f2ef..a25363c295 100644
--- a/cosid-core/src/main/java/me/ahoo/cosid/snowflake/SnowflakeIdState.java
+++ b/cosid-core/src/main/java/me/ahoo/cosid/snowflake/SnowflakeIdState.java
@@ -20,25 +20,42 @@
import java.util.Objects;
/**
- * SnowflakeId State.
+ * Immutable state object representing a parsed Snowflake ID.
+ *
+ * This class holds the decomposed components of a Snowflake ID:
+ * the raw ID, machine ID, sequence number, timestamp, and a human-readable
+ * friendly format ({@code timestamp-machineId-sequence}).
*
* @author ahoo wang
*/
@Immutable
public class SnowflakeIdState implements Comparable This class provides methods to parse a snowflake ID into its components
+ * (timestamp, machineId, sequence) and to reconstruct the raw ID from a
+ * friendly string format.
+ *
+ * The friendly format is: {@code timestamp-machineId-sequence} (e.g., "20210623131730192-1-0")
*
* @author ahoo wang
*/
@ThreadSafe
public abstract class SnowflakeIdStateParser {
+ /**
+ * Delimiter used in friendly ID format.
+ */
public static final String DELIMITER = "-";
+ /**
+ * Time zone used for timestamp conversion.
+ */
protected final ZoneId zoneId;
+ /**
+ * Epoch timestamp in milliseconds.
+ */
protected final long epoch;
+ /**
+ * Number of bits for sequence portion.
+ */
protected final int sequenceBit;
+ /**
+ * Mask for extracting sequence from raw ID.
+ */
protected final long sequenceMask;
+ /**
+ * Number of bits for machine ID portion.
+ */
protected final int machineBit;
+ /**
+ * Mask for extracting machine ID from raw ID.
+ */
protected final long machineMask;
+ /**
+ * Number of bits to shift machine ID left.
+ */
protected final int machineLeft;
+ /**
+ * Number of bits for timestamp portion.
+ */
protected final int timestampBit;
+ /**
+ * Mask for extracting timestamp from raw ID.
+ */
protected final long timestampMask;
+ /**
+ * Number of bits to shift timestamp left.
+ */
protected final int timestampLeft;
+ /**
+ * Whether to pad numeric fields with leading zeros.
+ */
protected final boolean padStart;
private final int machineCharSize;
private final int sequenceCharSize;
+ /**
+ * Creates a parser with default zone and no padding.
+ *
+ * @param epoch epoch timestamp in milliseconds
+ * @param timestampBit number of bits for timestamp
+ * @param machineBit number of bits for machine ID
+ * @param sequenceBit number of bits for sequence
+ */
public SnowflakeIdStateParser(long epoch, int timestampBit, int machineBit, int sequenceBit) {
this(epoch, timestampBit, machineBit, sequenceBit, ZoneId.systemDefault(), false);
}
+ /**
+ * Creates a parser with custom zone and padding settings.
+ *
+ * @param epoch epoch timestamp in milliseconds
+ * @param timestampBit number of bits for timestamp
+ * @param machineBit number of bits for machine ID
+ * @param sequenceBit number of bits for sequence
+ * @param zoneId time zone for timestamp conversion
+ * @param padStart whether to pad numeric fields with leading zeros
+ */
public SnowflakeIdStateParser(long epoch, int timestampBit, int machineBit, int sequenceBit, ZoneId zoneId, boolean padStart) {
this.epoch = epoch;
this.sequenceMask = getMask(sequenceBit);
@@ -76,28 +136,75 @@ public SnowflakeIdStateParser(long epoch, int timestampBit, int machineBit, int
this.sequenceCharSize = RadixIdConverter.maxCharSize(DECIMAL_RADIX, sequenceBit);
}
+ /**
+ * Gets the time zone used for timestamp conversion.
+ *
+ * @return the zone ID
+ */
public ZoneId getZoneId() {
return zoneId;
}
+ /**
+ * Checks if numeric fields are padded with leading zeros.
+ *
+ * @return true if padding is enabled
+ */
public boolean isPadStart() {
return padStart;
}
+ /**
+ * Gets the maximum character size for machine ID in decimal representation.
+ *
+ * @return the machine ID character size
+ */
public int getMachineCharSize() {
return machineCharSize;
}
+ /**
+ * Gets the maximum character size for sequence in decimal representation.
+ *
+ * @return the sequence character size
+ */
public int getSequenceCharSize() {
return sequenceCharSize;
}
+ /**
+ * Gets the date time formatter for parsing timestamps.
+ *
+ * @return the date time formatter
+ */
protected abstract DateTimeFormatter getDateTimeFormatter();
+ /**
+ * Converts a time difference to a LocalDateTime.
+ *
+ * @param diffTime time difference from epoch in the appropriate unit
+ * @return the corresponding LocalDateTime
+ */
protected abstract LocalDateTime getTimestamp(long diffTime);
+ /**
+ * Converts a LocalDateTime to time difference from epoch.
+ *
+ * @param timestamp the LocalDateTime to convert
+ * @return time difference from epoch
+ */
protected abstract long getDiffTime(LocalDateTime timestamp);
+ /**
+ * Parses a friendly ID string into SnowflakeIdState.
+ *
+ * Expected format: {@code timestamp-machineId-sequence}
+ *
+ * @param friendlyId the friendly ID string to parse
+ * @return the parsed state
+ * @throws IllegalArgumentException if format is invalid
+ * @throws NullPointerException if friendlyId is null
+ */
public SnowflakeIdState parse(String friendlyId) {
Preconditions.checkNotNull(friendlyId, "friendlyId can not be null!");
List Wraps a SnowflakeId with a string converter for generating
+ * string-based IDs while maintaining SnowflakeId properties.
*
* @author ahoo wang
*/
public class StringSnowflakeId extends StringIdGeneratorDecorator implements SnowflakeId {
private final SnowflakeId snowflakeId;
+ /**
+ * Creates a new StringSnowflakeId.
+ *
+ * @param actual the underlying SnowflakeId
+ * @param idConverter the converter for string generation
+ */
public StringSnowflakeId(SnowflakeId actual, IdConverter idConverter) {
super(actual, idConverter);
this.snowflakeId = actual;
diff --git a/cosid-core/src/main/java/me/ahoo/cosid/snowflake/exception/ClockBackwardsException.java b/cosid-core/src/main/java/me/ahoo/cosid/snowflake/exception/ClockBackwardsException.java
index 88463d99d5..3a8639c65b 100644
--- a/cosid-core/src/main/java/me/ahoo/cosid/snowflake/exception/ClockBackwardsException.java
+++ b/cosid-core/src/main/java/me/ahoo/cosid/snowflake/exception/ClockBackwardsException.java
@@ -16,7 +16,10 @@
import me.ahoo.cosid.CosIdException;
/**
- * Clock Backwards Exception.
+ * Exception thrown when system clock moves backwards.
+ *
+ * Indicates that the current system time is less than the last timestamp
+ * used for ID generation, which could cause ID duplication.
*
* @author ahoo wang
*/
@@ -24,16 +27,32 @@ public class ClockBackwardsException extends CosIdException {
private final long lastTimestamp;
private final long currentTimestamp;
+ /**
+ * Creates a new exception.
+ *
+ * @param lastTimestamp the last generated timestamp
+ * @param currentTimestamp the current system timestamp
+ */
public ClockBackwardsException(long lastTimestamp, long currentTimestamp) {
super(String.format("Clock moved backwards. Refusing to generate id. lastTimestamp:[%s] | currentTimestamp:[%s]", lastTimestamp, currentTimestamp));
this.lastTimestamp = lastTimestamp;
this.currentTimestamp = currentTimestamp;
}
+ /**
+ * Gets the last timestamp.
+ *
+ * @return the last timestamp
+ */
public long getLastTimestamp() {
return lastTimestamp;
}
+ /**
+ * Gets the current timestamp.
+ *
+ * @return the current timestamp
+ */
public long getCurrentTimestamp() {
return currentTimestamp;
}
diff --git a/cosid-core/src/main/java/me/ahoo/cosid/snowflake/exception/ClockTooManyBackwardsException.java b/cosid-core/src/main/java/me/ahoo/cosid/snowflake/exception/ClockTooManyBackwardsException.java
index 1edfe9c3ad..607fabd1e2 100644
--- a/cosid-core/src/main/java/me/ahoo/cosid/snowflake/exception/ClockTooManyBackwardsException.java
+++ b/cosid-core/src/main/java/me/ahoo/cosid/snowflake/exception/ClockTooManyBackwardsException.java
@@ -16,7 +16,10 @@
import me.ahoo.cosid.CosIdException;
/**
- * Clock Too Many Backwards Exception.
+ * Exception thrown when clock backwards exceeds threshold.
+ *
+ * Indicates that the system clock has moved backwards by more than
+ * the configured broken threshold, and the generator cannot recover.
*
* @author ahoo wang
*/
@@ -26,6 +29,13 @@ public class ClockTooManyBackwardsException extends CosIdException {
private final long currentTimestamp;
private final long brokenThreshold;
+ /**
+ * Creates a new exception.
+ *
+ * @param lastTimestamp the last generated timestamp
+ * @param currentTimestamp the current system timestamp
+ * @param brokenThreshold the configured broken threshold
+ */
public ClockTooManyBackwardsException(long lastTimestamp, long currentTimestamp, long brokenThreshold) {
super(String.format("Clock moved backwards too many. brokenThreshold:[%s] | lastTimestamp:[%s] | currentTimestamp:[%s]", brokenThreshold, lastTimestamp, currentTimestamp));
this.lastTimestamp = lastTimestamp;
@@ -33,14 +43,29 @@ public ClockTooManyBackwardsException(long lastTimestamp, long currentTimestamp,
this.brokenThreshold = brokenThreshold;
}
+ /**
+ * Gets the last timestamp.
+ *
+ * @return the last timestamp
+ */
public long getLastTimestamp() {
return lastTimestamp;
}
+ /**
+ * Gets the current timestamp.
+ *
+ * @return the current timestamp
+ */
public long getCurrentTimestamp() {
return currentTimestamp;
}
+ /**
+ * Gets the broken threshold.
+ *
+ * @return the broken threshold
+ */
public long getBrokenThreshold() {
return brokenThreshold;
}
diff --git a/cosid-core/src/main/java/me/ahoo/cosid/snowflake/exception/TimestampOverflowException.java b/cosid-core/src/main/java/me/ahoo/cosid/snowflake/exception/TimestampOverflowException.java
index 6e08b79685..edcedc41c6 100644
--- a/cosid-core/src/main/java/me/ahoo/cosid/snowflake/exception/TimestampOverflowException.java
+++ b/cosid-core/src/main/java/me/ahoo/cosid/snowflake/exception/TimestampOverflowException.java
@@ -18,7 +18,11 @@
import com.google.common.base.Strings;
/**
- * Timestamp Overflow Exception.
+ * Exception thrown when timestamp exceeds maximum value.
+ *
+ * Indicates that the timestamp portion of the ID has overflowed,
+ * meaning the generator has been in use for longer than the configured
+ * time range allows.
*
* @author ahoo wang
*/
@@ -27,6 +31,13 @@ public class TimestampOverflowException extends CosIdException {
private final long diffTimestamp;
private final long maxTimestamp;
+ /**
+ * Creates a new exception.
+ *
+ * @param epoch the configured epoch
+ * @param diffTimestamp the calculated timestamp difference
+ * @param maxTimestamp the maximum representable timestamp
+ */
public TimestampOverflowException(long epoch, long diffTimestamp, long maxTimestamp) {
super(Strings.lenientFormat("epoch:[%s] - diffTimestamp:[%s] can't be greater than maxTimestamp:[%s]", epoch, diffTimestamp, maxTimestamp));
this.epoch = epoch;
@@ -34,14 +45,29 @@ public TimestampOverflowException(long epoch, long diffTimestamp, long maxTimest
this.maxTimestamp = maxTimestamp;
}
+ /**
+ * Gets the epoch.
+ *
+ * @return the epoch
+ */
public long getEpoch() {
return epoch;
}
+ /**
+ * Gets the diff timestamp.
+ *
+ * @return the diff timestamp
+ */
public long getDiffTimestamp() {
return diffTimestamp;
}
+ /**
+ * Gets the max timestamp.
+ *
+ * @return the max timestamp
+ */
public long getMaxTimestamp() {
return maxTimestamp;
}
diff --git a/cosid-core/src/main/java/me/ahoo/cosid/stat/SimpleStat.java b/cosid-core/src/main/java/me/ahoo/cosid/stat/SimpleStat.java
index 8982c12aec..2a154a40ce 100644
--- a/cosid-core/src/main/java/me/ahoo/cosid/stat/SimpleStat.java
+++ b/cosid-core/src/main/java/me/ahoo/cosid/stat/SimpleStat.java
@@ -16,6 +16,11 @@
import lombok.AllArgsConstructor;
import lombok.Data;
+/**
+ * Simple stat implementation wrapping another stat.
+ *
+ * @author ahoo wang
+ */
@AllArgsConstructor
@Data
public class SimpleStat implements Stat {
diff --git a/cosid-core/src/main/java/me/ahoo/cosid/stat/Stat.java b/cosid-core/src/main/java/me/ahoo/cosid/stat/Stat.java
index 14e430eed2..46cdb11366 100644
--- a/cosid-core/src/main/java/me/ahoo/cosid/stat/Stat.java
+++ b/cosid-core/src/main/java/me/ahoo/cosid/stat/Stat.java
@@ -15,19 +15,45 @@
import org.jspecify.annotations.Nullable;
+/**
+ * Statistical information interface.
+ */
public interface Stat {
+ /**
+ * Gets the kind/type of this stat.
+ *
+ * @return the kind
+ */
String getKind();
+ /**
+ * Gets the wrapped actual stat.
+ *
+ * @return the actual stat or null
+ */
@Nullable
default Stat getActual() {
return null;
}
+ /**
+ * Creates a simple stat with the specified kind and actual.
+ *
+ * @param kind the kind
+ * @param actual the actual stat
+ * @return the stat
+ */
static Stat simple(String kind, @Nullable Stat actual) {
return new SimpleStat(kind, actual);
}
+ /**
+ * Creates a simple stat with the specified kind.
+ *
+ * @param kind the kind
+ * @return the stat
+ */
static Stat simple(String kind) {
return simple(kind, null);
}
diff --git a/cosid-core/src/main/java/me/ahoo/cosid/stat/Statistical.java b/cosid-core/src/main/java/me/ahoo/cosid/stat/Statistical.java
index abc45f0ac0..d2cbf066e1 100644
--- a/cosid-core/src/main/java/me/ahoo/cosid/stat/Statistical.java
+++ b/cosid-core/src/main/java/me/ahoo/cosid/stat/Statistical.java
@@ -13,7 +13,15 @@
package me.ahoo.cosid.stat;
+/**
+ * Interface for objects that can provide statistical information.
+ */
@FunctionalInterface
public interface Statistical {
+ /**
+ * Gets statistical information.
+ *
+ * @return the stat
+ */
Stat stat();
}
diff --git a/cosid-core/src/main/java/me/ahoo/cosid/stat/converter/DatePrefixConverterStat.java b/cosid-core/src/main/java/me/ahoo/cosid/stat/converter/DatePrefixConverterStat.java
index 6a42b66191..4f731d41dc 100644
--- a/cosid-core/src/main/java/me/ahoo/cosid/stat/converter/DatePrefixConverterStat.java
+++ b/cosid-core/src/main/java/me/ahoo/cosid/stat/converter/DatePrefixConverterStat.java
@@ -18,6 +18,11 @@
import lombok.AllArgsConstructor;
import lombok.Data;
+/**
+ * Date prefix converter stat with pattern configuration.
+ *
+ * @author ahoo wang
+ */
@AllArgsConstructor
@Data
public final class DatePrefixConverterStat implements Stat {
diff --git a/cosid-core/src/main/java/me/ahoo/cosid/stat/converter/GroupedPrefixConverterStat.java b/cosid-core/src/main/java/me/ahoo/cosid/stat/converter/GroupedPrefixConverterStat.java
index a48d307ee1..a8cfb027fd 100644
--- a/cosid-core/src/main/java/me/ahoo/cosid/stat/converter/GroupedPrefixConverterStat.java
+++ b/cosid-core/src/main/java/me/ahoo/cosid/stat/converter/GroupedPrefixConverterStat.java
@@ -18,6 +18,11 @@
import lombok.AllArgsConstructor;
import lombok.Data;
+/**
+ * Grouped prefix converter stat with delimiter configuration.
+ *
+ * @author ahoo wang
+ */
@AllArgsConstructor
@Data
public final class GroupedPrefixConverterStat implements Stat {
diff --git a/cosid-core/src/main/java/me/ahoo/cosid/stat/converter/PrefixConverterStat.java b/cosid-core/src/main/java/me/ahoo/cosid/stat/converter/PrefixConverterStat.java
index 28089cf4f5..c5b71c7c41 100644
--- a/cosid-core/src/main/java/me/ahoo/cosid/stat/converter/PrefixConverterStat.java
+++ b/cosid-core/src/main/java/me/ahoo/cosid/stat/converter/PrefixConverterStat.java
@@ -18,6 +18,11 @@
import lombok.AllArgsConstructor;
import lombok.Data;
+/**
+ * Prefix converter stat with prefix configuration.
+ *
+ * @author ahoo wang
+ */
@AllArgsConstructor
@Data
public final class PrefixConverterStat implements Stat {
diff --git a/cosid-core/src/main/java/me/ahoo/cosid/stat/converter/RadixConverterStat.java b/cosid-core/src/main/java/me/ahoo/cosid/stat/converter/RadixConverterStat.java
index dc3f8e9e71..8076770d85 100644
--- a/cosid-core/src/main/java/me/ahoo/cosid/stat/converter/RadixConverterStat.java
+++ b/cosid-core/src/main/java/me/ahoo/cosid/stat/converter/RadixConverterStat.java
@@ -18,6 +18,11 @@
import lombok.AllArgsConstructor;
import lombok.Data;
+/**
+ * Radix converter stat with radix configuration.
+ *
+ * @author ahoo wang
+ */
@AllArgsConstructor
@Data
public final class RadixConverterStat implements Stat {
diff --git a/cosid-core/src/main/java/me/ahoo/cosid/stat/converter/SnowflakeFriendlyIdConverterStat.java b/cosid-core/src/main/java/me/ahoo/cosid/stat/converter/SnowflakeFriendlyIdConverterStat.java
index 5a333f7355..2740f9a38b 100644
--- a/cosid-core/src/main/java/me/ahoo/cosid/stat/converter/SnowflakeFriendlyIdConverterStat.java
+++ b/cosid-core/src/main/java/me/ahoo/cosid/stat/converter/SnowflakeFriendlyIdConverterStat.java
@@ -18,6 +18,11 @@
import lombok.AllArgsConstructor;
import lombok.Data;
+/**
+ * Snowflake friendly ID converter stat with configuration.
+ *
+ * @author ahoo wang
+ */
@AllArgsConstructor
@Data
public class SnowflakeFriendlyIdConverterStat implements Stat {
diff --git a/cosid-core/src/main/java/me/ahoo/cosid/stat/converter/SuffixConverterStat.java b/cosid-core/src/main/java/me/ahoo/cosid/stat/converter/SuffixConverterStat.java
index 59e7f08461..a337ece21e 100644
--- a/cosid-core/src/main/java/me/ahoo/cosid/stat/converter/SuffixConverterStat.java
+++ b/cosid-core/src/main/java/me/ahoo/cosid/stat/converter/SuffixConverterStat.java
@@ -18,6 +18,11 @@
import lombok.AllArgsConstructor;
import lombok.Data;
+/**
+ * Suffix converter stat with suffix configuration.
+ *
+ * @author ahoo wang
+ */
@AllArgsConstructor
@Data
public final class SuffixConverterStat implements Stat {
diff --git a/cosid-core/src/main/java/me/ahoo/cosid/stat/converter/ToStringConverterStat.java b/cosid-core/src/main/java/me/ahoo/cosid/stat/converter/ToStringConverterStat.java
index ed9bdf22ff..cad80edad9 100644
--- a/cosid-core/src/main/java/me/ahoo/cosid/stat/converter/ToStringConverterStat.java
+++ b/cosid-core/src/main/java/me/ahoo/cosid/stat/converter/ToStringConverterStat.java
@@ -18,6 +18,11 @@
import lombok.AllArgsConstructor;
import lombok.Data;
+/**
+ * ToString converter stat with padding configuration.
+ *
+ * @author ahoo wang
+ */
@AllArgsConstructor
@Data
public final class ToStringConverterStat implements Stat {
diff --git a/cosid-core/src/main/java/me/ahoo/cosid/stat/generator/CosIdGeneratorStat.java b/cosid-core/src/main/java/me/ahoo/cosid/stat/generator/CosIdGeneratorStat.java
index 14a18519a9..51a322eb5e 100644
--- a/cosid-core/src/main/java/me/ahoo/cosid/stat/generator/CosIdGeneratorStat.java
+++ b/cosid-core/src/main/java/me/ahoo/cosid/stat/generator/CosIdGeneratorStat.java
@@ -18,6 +18,11 @@
import lombok.AllArgsConstructor;
import lombok.Data;
+/**
+ * CosId generator stat with machine and timestamp info.
+ *
+ * @author ahoo wang
+ */
@AllArgsConstructor
@Data
public final class CosIdGeneratorStat implements IdGeneratorStat {
diff --git a/cosid-core/src/main/java/me/ahoo/cosid/stat/generator/IdGeneratorStat.java b/cosid-core/src/main/java/me/ahoo/cosid/stat/generator/IdGeneratorStat.java
index 69639184bc..995bc060d4 100644
--- a/cosid-core/src/main/java/me/ahoo/cosid/stat/generator/IdGeneratorStat.java
+++ b/cosid-core/src/main/java/me/ahoo/cosid/stat/generator/IdGeneratorStat.java
@@ -17,20 +17,43 @@
import org.jspecify.annotations.Nullable;
+/**
+ * Statistical information for ID generators.
+ */
public interface IdGeneratorStat extends Stat {
@Nullable
@Override
default IdGeneratorStat getActual() {
return null;
}
-
+
+ /**
+ * Gets the converter stat.
+ *
+ * @return the converter stat or null
+ */
@Nullable
Stat getConverter();
-
+
+ /**
+ * Creates a simple stat with the specified kind and converter.
+ *
+ * @param kind the kind
+ * @param actual the actual stat
+ * @param converter the converter stat
+ * @return the stat
+ */
static IdGeneratorStat simple(String kind, @Nullable IdGeneratorStat actual, Stat converter) {
return new SimpleIdGeneratorStat(kind, actual, converter);
}
-
+
+ /**
+ * Creates a simple stat with the specified kind and converter.
+ *
+ * @param kind the kind
+ * @param converter the converter stat
+ * @return the stat
+ */
static IdGeneratorStat simple(String kind, Stat converter) {
return simple(kind, null, converter);
}
diff --git a/cosid-core/src/main/java/me/ahoo/cosid/stat/generator/SegmentIdStat.java b/cosid-core/src/main/java/me/ahoo/cosid/stat/generator/SegmentIdStat.java
index 8d78fb92ac..c216e765fd 100644
--- a/cosid-core/src/main/java/me/ahoo/cosid/stat/generator/SegmentIdStat.java
+++ b/cosid-core/src/main/java/me/ahoo/cosid/stat/generator/SegmentIdStat.java
@@ -19,6 +19,11 @@
import lombok.AllArgsConstructor;
import lombok.Data;
+/**
+ * Segment ID generator stat with segment metadata.
+ *
+ * @author ahoo wang
+ */
@AllArgsConstructor
@Data
public final class SegmentIdStat implements IdGeneratorStat {
diff --git a/cosid-core/src/main/java/me/ahoo/cosid/stat/generator/SimpleIdGeneratorStat.java b/cosid-core/src/main/java/me/ahoo/cosid/stat/generator/SimpleIdGeneratorStat.java
index 517b765617..8d476eb6be 100644
--- a/cosid-core/src/main/java/me/ahoo/cosid/stat/generator/SimpleIdGeneratorStat.java
+++ b/cosid-core/src/main/java/me/ahoo/cosid/stat/generator/SimpleIdGeneratorStat.java
@@ -18,6 +18,11 @@
import lombok.AllArgsConstructor;
import lombok.Data;
+/**
+ * Simple ID generator stat implementation.
+ *
+ * @author ahoo wang
+ */
@AllArgsConstructor
@Data
public final class SimpleIdGeneratorStat implements IdGeneratorStat {
diff --git a/cosid-core/src/main/java/me/ahoo/cosid/stat/generator/SnowflakeIdStat.java b/cosid-core/src/main/java/me/ahoo/cosid/stat/generator/SnowflakeIdStat.java
index 6a92bfdd3f..c94ec19011 100644
--- a/cosid-core/src/main/java/me/ahoo/cosid/stat/generator/SnowflakeIdStat.java
+++ b/cosid-core/src/main/java/me/ahoo/cosid/stat/generator/SnowflakeIdStat.java
@@ -18,6 +18,11 @@
import lombok.AllArgsConstructor;
import lombok.Data;
+/**
+ * Snowflake ID generator stat with Snowflake configuration.
+ *
+ * @author ahoo wang
+ */
@AllArgsConstructor
@Data
public final class SnowflakeIdStat implements IdGeneratorStat {
diff --git a/cosid-core/src/main/java/me/ahoo/cosid/uncertainty/OriginalIdOverflowException.java b/cosid-core/src/main/java/me/ahoo/cosid/uncertainty/OriginalIdOverflowException.java
index 0f80c1c3bf..bd51fbfcb5 100644
--- a/cosid-core/src/main/java/me/ahoo/cosid/uncertainty/OriginalIdOverflowException.java
+++ b/cosid-core/src/main/java/me/ahoo/cosid/uncertainty/OriginalIdOverflowException.java
@@ -17,26 +17,53 @@
import com.google.common.base.Strings;
+/**
+ * Exception thrown when original ID exceeds maximum representable value.
+ *
+ * @author ahoo wang
+ */
public class OriginalIdOverflowException extends CosIdException {
private final long originalId;
private final int originalIdBits;
private final long maxOriginalId;
-
+
+ /**
+ * Creates a new exception.
+ *
+ * @param originalId the original ID value
+ * @param originalIdBits the number of bits for the original ID
+ * @param maxOriginalId the maximum representable ID
+ */
public OriginalIdOverflowException(long originalId, int originalIdBits, long maxOriginalId) {
super(Strings.lenientFormat("OriginalId[%s] overflow - originalIdBits[%s] - maxOriginalId[%s].", originalId, originalIdBits, maxOriginalId));
this.originalId = originalId;
this.originalIdBits = originalIdBits;
this.maxOriginalId = maxOriginalId;
}
-
+
+ /**
+ * Gets the original ID.
+ *
+ * @return the original ID
+ */
public long originalId() {
return originalId;
}
-
+
+ /**
+ * Gets the original ID bits.
+ *
+ * @return the bits
+ */
public int originalIdBits() {
return originalIdBits;
}
-
+
+ /**
+ * Gets the max original ID.
+ *
+ * @return the max ID
+ */
public long maxOriginalId() {
return maxOriginalId;
}
diff --git a/cosid-core/src/main/java/me/ahoo/cosid/util/ProcessId.java b/cosid-core/src/main/java/me/ahoo/cosid/util/ProcessId.java
index 9b5c1264de..b4ccdfaac9 100644
--- a/cosid-core/src/main/java/me/ahoo/cosid/util/ProcessId.java
+++ b/cosid-core/src/main/java/me/ahoo/cosid/util/ProcessId.java
@@ -18,37 +18,48 @@
import java.lang.management.ManagementFactory;
/**
- * get current process id .
+ * Utility for getting current process information.
+ *
+ * Provides access to the current process ID and process name,
+ * useful for machine identification in distributed ID generation.
*
* @author ahoo wang
*/
@Immutable
public enum ProcessId {
+ /**
+ * Singleton instance for current process.
+ */
CURRENT;
-
+
private final int processId;
-
+
ProcessId() {
this.processId = getCurrentProcessId();
}
-
+
+ /**
+ * Gets the process ID.
+ *
+ * @return the process ID
+ */
public int getProcessId() {
return processId;
}
-
+
/**
- * get current process name .
+ * Gets the current process name.
*
- * @return process name
+ * @return process name (typically in format pid@hostname)
*/
public static String getCurrentProcessName() {
return ManagementFactory.getRuntimeMXBean().getName();
}
-
+
/**
- * get current process id .
+ * Gets the current process ID.
*
- * @return process id
+ * @return the process ID extracted from process name
*/
public static int getCurrentProcessId() {
String processName = getCurrentProcessName();
+ *
*
* @author ahoo wang
*/
@@ -30,20 +36,22 @@
@Documented
@Retention(RetentionPolicy.RUNTIME)
public @interface CosId {
+ /**
+ * Default field name.
+ */
String DEFAULT_FIELD = "id";
/**
- * id generator name.
- * {@link IdGeneratorProvider#get(String)}
+ * Gets the ID generator name.
*
- * @return id generator name
+ * @return the generator name
*/
String value() default IdGeneratorProvider.SHARE;
/**
- * cosid field.
+ * Gets the ID field name (for type-level annotation).
*
- * @return field name of id.
+ * @return the field name
*/
String field() default DEFAULT_FIELD;
}
diff --git a/cosid-core/src/main/java/me/ahoo/cosid/converter/DatePrefixIdConverter.java b/cosid-core/src/main/java/me/ahoo/cosid/converter/DatePrefixIdConverter.java
index a39fa21cb8..d4e915d190 100644
--- a/cosid-core/src/main/java/me/ahoo/cosid/converter/DatePrefixIdConverter.java
+++ b/cosid-core/src/main/java/me/ahoo/cosid/converter/DatePrefixIdConverter.java
@@ -23,12 +23,27 @@
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
+/**
+ * ID converter that prepends a date prefix to the ID string.
+ *
+ *
+ *
+ *
+ * @author ahoo wang
*/
public final class CosIdState implements Comparable
- * 主要针对以下问题:
- * -- 使用{@link java.util.HashSet}导致的内存空间浪费
- * -- 添加元素时导致的集合膨胀(也可以通过给定 expectedSize 计算准确 capacity 就像 {@link Sets#newHashSetWithExpectedSize(int)})
- *
+ * Exact-size collection optimized for known node counts.
+ *
+ * 


+ *
+ *
+ * @param machineId the machine ID (max 7)
* @return MillisecondSnowflakeId
*/
public static MillisecondSnowflakeId ofMillisecond(int machineId) {
@@ -51,18 +82,34 @@ public static MillisecondSnowflakeId ofMillisecond(int machineId) {
checkTotalBit(timestampBit, machineBit, sequenceBit);
return ofMillisecond(CosId.COSID_EPOCH_SECOND, timestampBit, machineBit, sequenceBit, machineId, SnowflakeId.defaultSequenceResetThreshold(sequenceBit));
}
-
+
+ /**
+ * Creates a safe second SnowflakeId.
+ *
+ * @param epoch epoch timestamp
+ * @param timestampBit bits for timestamp
+ * @param machineBit bits for machine ID
+ * @param sequenceBit bits for sequence
+ * @param machineId the machine ID
+ * @param sequenceResetThreshold threshold for sequence reset
+ * @return a new SecondSnowflakeId
+ */
public static SecondSnowflakeId ofSecond(long epoch, int timestampBit, int machineBit, int sequenceBit, int machineId, long sequenceResetThreshold) {
checkTotalBit(timestampBit, machineBit, sequenceBit);
return new SecondSnowflakeId(epoch, timestampBit, machineBit, sequenceBit, machineId, sequenceResetThreshold);
}
-
+
/**
- * Max Sequence (19 bits) = (1<<19) = 524288 (TPS).
- * Max Machine (3 bits) = 1<<3 = 8
- * Max Timestamp = 2147483647 s ~~ 68 years
+ * Creates a safe second SnowflakeId with default safe configuration.
*
- * @param machineId 服务实例编号
+ *
+ *
+ *
+ * @param machineId the machine ID (max 7)
* @return SecondSnowflakeId
*/
public static SecondSnowflakeId ofSecond(int machineId) {
@@ -72,7 +119,7 @@ public static SecondSnowflakeId ofSecond(int machineId) {
checkTotalBit(timestampBit, machineBit, sequenceBit);
return ofSecond(CosId.COSID_EPOCH_SECOND, timestampBit, machineBit, sequenceBit, machineId, SnowflakeId.defaultSequenceResetThreshold(sequenceBit));
}
-
+
private static void checkTotalBit(int timestampBit, int machineBit, int sequenceBit) {
if (timestampBit + machineBit + sequenceBit > JAVA_SCRIPT_MAX_SAFE_NUMBER_BIT) {
throw new IllegalArgumentException(String.format("total bit can't be greater than JAVA_SCRIPT_MAX_SAFE_NUMBER_BIT:[%s].", JAVA_SCRIPT_MAX_SAFE_NUMBER_BIT));
diff --git a/cosid-core/src/main/java/me/ahoo/cosid/snowflake/SecondSnowflakeId.java b/cosid-core/src/main/java/me/ahoo/cosid/snowflake/SecondSnowflakeId.java
index a59201894e..9690c5b0c7 100644
--- a/cosid-core/src/main/java/me/ahoo/cosid/snowflake/SecondSnowflakeId.java
+++ b/cosid-core/src/main/java/me/ahoo/cosid/snowflake/SecondSnowflakeId.java
@@ -18,33 +18,86 @@
import java.util.concurrent.TimeUnit;
/**
- * Second SnowflakeId.
+ * Second-based Snowflake ID generator.
+ *
+ *
+ *
*
* @author ahoo wang
- **/
+ */
public class SecondSnowflakeId extends AbstractSnowflakeId {
-
+
+ /**
+ * Default number of timestamp bits (31 bits).
+ */
public static final int DEFAULT_TIMESTAMP_BIT = 31;
+ /**
+ * Default number of machine ID bits (10 bits).
+ */
public static final int DEFAULT_MACHINE_BIT = 10;
+ /**
+ * Default number of sequence bits (22 bits).
+ */
public static final int DEFAULT_SEQUENCE_BIT = 22;
+ /**
+ * Default sequence reset threshold (half of max sequence).
+ */
public static final long DEFAULT_SEQUENCE_RESET_THRESHOLD = ~(-1L << (DEFAULT_SEQUENCE_BIT - 1));
-
+
+ /**
+ * Creates a SecondSnowflakeId with default configuration.
+ *
+ * @param machineId the machine ID
+ */
public SecondSnowflakeId(int machineId) {
this(CosId.COSID_EPOCH_SECOND, DEFAULT_TIMESTAMP_BIT, DEFAULT_MACHINE_BIT, DEFAULT_SEQUENCE_BIT, machineId, DEFAULT_SEQUENCE_RESET_THRESHOLD);
}
-
+
+ /**
+ * Creates a SecondSnowflakeId with custom machine bits.
+ *
+ * @param machineBit the number of bits for machine ID
+ * @param machineId the machine ID
+ */
public SecondSnowflakeId(int machineBit, int machineId) {
super(CosId.COSID_EPOCH_SECOND, DEFAULT_TIMESTAMP_BIT, machineBit, DEFAULT_SEQUENCE_BIT, machineId, DEFAULT_SEQUENCE_RESET_THRESHOLD);
}
-
+
+ /**
+ * Creates a SecondSnowflakeId with custom bit configuration.
+ *
+ * @param epoch epoch timestamp in milliseconds
+ * @param timestampBit number of bits for timestamp
+ * @param machineBit number of bits for machine ID
+ * @param sequenceBit number of bits for sequence
+ * @param machineId the machine ID
+ */
public SecondSnowflakeId(long epoch, int timestampBit, int machineBit, int sequenceBit, int machineId) {
super(epoch, timestampBit, machineBit, sequenceBit, machineId, SnowflakeId.defaultSequenceResetThreshold(sequenceBit));
}
-
+
+ /**
+ * Creates a SecondSnowflakeId with full custom configuration.
+ *
+ * @param epoch epoch timestamp in milliseconds
+ * @param timestampBit number of bits for timestamp
+ * @param machineBit number of bits for machine ID
+ * @param sequenceBit number of bits for sequence
+ * @param machineId the machine ID
+ * @param sequenceResetThreshold threshold for resetting sequence
+ */
public SecondSnowflakeId(long epoch, int timestampBit, int machineBit, int sequenceBit, int machineId, long sequenceResetThreshold) {
super(epoch, timestampBit, machineBit, sequenceBit, machineId, sequenceResetThreshold);
}
-
+
@Override
protected long getCurrentTime() {
return TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis());
diff --git a/cosid-core/src/main/java/me/ahoo/cosid/snowflake/SecondSnowflakeIdStateParser.java b/cosid-core/src/main/java/me/ahoo/cosid/snowflake/SecondSnowflakeIdStateParser.java
index 63a08cf99c..e8c35cb092 100644
--- a/cosid-core/src/main/java/me/ahoo/cosid/snowflake/SecondSnowflakeIdStateParser.java
+++ b/cosid-core/src/main/java/me/ahoo/cosid/snowflake/SecondSnowflakeIdStateParser.java
@@ -28,12 +28,18 @@
import java.time.format.DateTimeFormatterBuilder;
/**
- * Second SnowflakeId State Parser.
+ * Parser for second-based SnowflakeId state.
+ *
+ *