Skip to content

Commit

Permalink
FlakeIdGenerator advanced configuration (#16278)
Browse files Browse the repository at this point in the history
FlakeIdGenerator advanced configuration. Externalizes the following properties:
- epochStart
- bitsTimestamp
- bitsSequence
- bitsNodeId
- allowedFutureMillis

Fixes #14150

Authored by: @lukasherman
  • Loading branch information
lukasherman authored and mmedenjak committed Jan 7, 2020
1 parent 33fc094 commit 7119690
Show file tree
Hide file tree
Showing 37 changed files with 660 additions and 373 deletions.
54 changes: 41 additions & 13 deletions hazelcast-spring/src/main/resources/hazelcast-spring-4.0.xsd
Expand Up @@ -3273,21 +3273,11 @@
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="idOffset" type="xs:long" default="0" use="optional">
<xs:attribute name="epochStart" type="xs:long" default="1514764800000" use="optional">
<xs:annotation>
<xs:documentation>
Sets the offset that will be added to the returned IDs. Default value is 0. Setting might be
useful when migrating from IdGenerator, default value works for all green-field projects.

For example: Largest ID returned from IdGenerator is 150. FlakeIdGenerator now returns
100. If you configure idOffset of 50 and stop using the IdGenerator, the next ID from
FlakeIdGenerator will be 151 or larger and no duplicate IDs will be generated. In real-life,
the IDs are much larger. You also need to add a reserve to the offset because the IDs
from FlakeIdGenerator are only roughly ordered. Recommended reserve is 2^38, that is
274877906944.

Negative values are allowed to increase the lifespan of the generator, however keep in
mind that the generated IDs might also be negative.
Sets the offset of timestamp component. Time unit is milliseconds, default is 1514764800000
(1.1.2018 0:00 UTC).
</xs:documentation>
</xs:annotation>
</xs:attribute>
Expand All @@ -3301,6 +3291,44 @@
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="bitsSequence" default="6" use="optional">
<xs:annotation>
<xs:documentation>
Sets the bit-length of the sequence component, default is 6 bits.
</xs:documentation>
</xs:annotation>
<xs:simpleType>
<xs:restriction base="xs:int">
<xs:minInclusive value="0" />
<xs:maxInclusive value="63" />
</xs:restriction>
</xs:simpleType>
</xs:attribute>
<xs:attribute name="bitsNodeId" default="16" use="optional">
<xs:annotation>
<xs:documentation>
Sets the bit-length of node id component. Default value is 16 bits.
</xs:documentation>
</xs:annotation>
<xs:simpleType>
<xs:restriction base="xs:int">
<xs:minInclusive value="0" />
<xs:maxInclusive value="63" />
</xs:restriction>
</xs:simpleType>
</xs:attribute>
<xs:attribute name="allowedFutureMillis" default="15000" use="optional">
<xs:annotation>
<xs:documentation>
Sets how far to the future is the generator allowed to go to generate IDs without blocking, default is 15 seconds.
</xs:documentation>
</xs:annotation>
<xs:simpleType>
<xs:restriction base="xs:long">
<xs:minInclusive value="0"/>
</xs:restriction>
</xs:simpleType>
</xs:attribute>
<xs:attribute name="statistics-enabled" type="parameterized-boolean" use="optional" default="true">
<xs:annotation>
<xs:documentation>
Expand Down
Expand Up @@ -471,8 +471,11 @@ public void testMemberFlakeIdGeneratorConfig() {
FlakeIdGeneratorConfig c = instance.getConfig().findFlakeIdGeneratorConfig("flakeIdGenerator");
assertEquals(3, c.getPrefetchCount());
assertEquals(10L, c.getPrefetchValidityMillis());
assertEquals(20L, c.getIdOffset());
assertEquals(30L, c.getNodeIdOffset());
assertEquals(22, c.getBitsSequence());
assertEquals(33, c.getBitsNodeId());
assertEquals(20000L, c.getAllowedFutureMillis());
assertFalse(c.isStatisticsEnabled());
assertEquals("flakeIdGenerator*", c.getName());
assertFalse(c.isStatisticsEnabled());
}
Expand Down
Expand Up @@ -822,8 +822,10 @@
</hz:encryption-at-rest>
</hz:hot-restart-persistence>

<hz:flake-id-generator name="flakeIdGenerator*" prefetchCount="3" prefetchValidityMillis="10" idOffset="20"
nodeIdOffset="30" statistics-enabled="false" />
<hz:flake-id-generator name="flakeIdGenerator*" prefetchCount="3" prefetchValidityMillis="10"
epochStart="1514764800001" nodeIdOffset="30"
bitsSequence="22" bitsNodeId="33" allowedFutureMillis="20000"
statistics-enabled="false" />

<hz:crdt-replication max-concurrent-replication-targets="10" replication-period-millis="2000" />

Expand Down
Expand Up @@ -347,9 +347,12 @@ public Config addFlakeIdGeneratorConfig(FlakeIdGeneratorConfig flakeIdGeneratorC
flakeIdGeneratorConfig.getName(),
flakeIdGeneratorConfig.getPrefetchCount(),
flakeIdGeneratorConfig.getPrefetchValidityMillis(),
flakeIdGeneratorConfig.getIdOffset(),
flakeIdGeneratorConfig.isStatisticsEnabled(),
flakeIdGeneratorConfig.getNodeIdOffset());
flakeIdGeneratorConfig.getNodeIdOffset(),
flakeIdGeneratorConfig.getEpochStart(),
flakeIdGeneratorConfig.getBitsSequence(),
flakeIdGeneratorConfig.getBitsNodeId(),
flakeIdGeneratorConfig.getAllowedFutureMillis());
invoke(request);
return this;
}
Expand Down
Expand Up @@ -38,18 +38,21 @@
* If a flake ID generator configuration for the same name already exists, then
* the new configuration is ignored and the existing one is preserved.
*/
@Generated("f998bdef9b5d75f20d026bfa302fce1a")
@Generated("de4b2622a6be3436137c65589607ba0d")
public final class DynamicConfigAddFlakeIdGeneratorConfigCodec {
//hex: 0x1B0F00
public static final int REQUEST_MESSAGE_TYPE = 1773312;
//hex: 0x1B0F01
public static final int RESPONSE_MESSAGE_TYPE = 1773313;
private static final int REQUEST_PREFETCH_COUNT_FIELD_OFFSET = PARTITION_ID_FIELD_OFFSET + INT_SIZE_IN_BYTES;
private static final int REQUEST_PREFETCH_VALIDITY_FIELD_OFFSET = REQUEST_PREFETCH_COUNT_FIELD_OFFSET + INT_SIZE_IN_BYTES;
private static final int REQUEST_ID_OFFSET_FIELD_OFFSET = REQUEST_PREFETCH_VALIDITY_FIELD_OFFSET + LONG_SIZE_IN_BYTES;
private static final int REQUEST_STATISTICS_ENABLED_FIELD_OFFSET = REQUEST_ID_OFFSET_FIELD_OFFSET + LONG_SIZE_IN_BYTES;
private static final int REQUEST_STATISTICS_ENABLED_FIELD_OFFSET = REQUEST_PREFETCH_VALIDITY_FIELD_OFFSET + LONG_SIZE_IN_BYTES;
private static final int REQUEST_NODE_ID_OFFSET_FIELD_OFFSET = REQUEST_STATISTICS_ENABLED_FIELD_OFFSET + BOOLEAN_SIZE_IN_BYTES;
private static final int REQUEST_INITIAL_FRAME_SIZE = REQUEST_NODE_ID_OFFSET_FIELD_OFFSET + LONG_SIZE_IN_BYTES;
private static final int REQUEST_EPOCH_START_FIELD_OFFSET = REQUEST_NODE_ID_OFFSET_FIELD_OFFSET + LONG_SIZE_IN_BYTES;
private static final int REQUEST_BITS_SEQUENCE_FIELD_OFFSET = REQUEST_EPOCH_START_FIELD_OFFSET + LONG_SIZE_IN_BYTES;
private static final int REQUEST_BITS_NODE_ID_FIELD_OFFSET = REQUEST_BITS_SEQUENCE_FIELD_OFFSET + INT_SIZE_IN_BYTES;
private static final int REQUEST_ALLOWED_FUTURE_MILLIS_FIELD_OFFSET = REQUEST_BITS_NODE_ID_FIELD_OFFSET + INT_SIZE_IN_BYTES;
private static final int REQUEST_INITIAL_FRAME_SIZE = REQUEST_ALLOWED_FUTURE_MILLIS_FIELD_OFFSET + LONG_SIZE_IN_BYTES;
private static final int RESPONSE_INITIAL_FRAME_SIZE = RESPONSE_BACKUP_ACKS_FIELD_OFFSET + INT_SIZE_IN_BYTES;

private DynamicConfigAddFlakeIdGeneratorConfigCodec() {
Expand All @@ -73,11 +76,6 @@ public static class RequestParameters {
*/
public long prefetchValidity;

/**
* TODO DOC
*/
public long idOffset;

/**
* {@code true} to enable gathering of statistics, otherwise {@code false}
*/
Expand All @@ -87,19 +85,42 @@ public static class RequestParameters {
* TODO DOC
*/
public long nodeIdOffset;

/**
* offset of timestamp component in milliseconds
*/
public long epochStart;

/**
* bit length of sequence component
*/
public int bitsSequence;

/**
* bit length of node id component
*/
public int bitsNodeId;

/**
* how far to the future is it allowed to go to generate IDs
*/
public long allowedFutureMillis;
}

public static ClientMessage encodeRequest(java.lang.String name, int prefetchCount, long prefetchValidity, long idOffset, boolean statisticsEnabled, long nodeIdOffset) {
public static ClientMessage encodeRequest(java.lang.String name, int prefetchCount, long prefetchValidity, boolean statisticsEnabled, long nodeIdOffset, long epochStart, int bitsSequence, int bitsNodeId, long allowedFutureMillis) {
ClientMessage clientMessage = ClientMessage.createForEncode();
clientMessage.setRetryable(false);
clientMessage.setOperationName("DynamicConfig.AddFlakeIdGeneratorConfig");
ClientMessage.Frame initialFrame = new ClientMessage.Frame(new byte[REQUEST_INITIAL_FRAME_SIZE], UNFRAGMENTED_MESSAGE);
encodeInt(initialFrame.content, TYPE_FIELD_OFFSET, REQUEST_MESSAGE_TYPE);
encodeInt(initialFrame.content, REQUEST_PREFETCH_COUNT_FIELD_OFFSET, prefetchCount);
encodeLong(initialFrame.content, REQUEST_PREFETCH_VALIDITY_FIELD_OFFSET, prefetchValidity);
encodeLong(initialFrame.content, REQUEST_ID_OFFSET_FIELD_OFFSET, idOffset);
encodeBoolean(initialFrame.content, REQUEST_STATISTICS_ENABLED_FIELD_OFFSET, statisticsEnabled);
encodeLong(initialFrame.content, REQUEST_NODE_ID_OFFSET_FIELD_OFFSET, nodeIdOffset);
encodeLong(initialFrame.content, REQUEST_EPOCH_START_FIELD_OFFSET, epochStart);
encodeInt(initialFrame.content, REQUEST_BITS_SEQUENCE_FIELD_OFFSET, bitsSequence);
encodeInt(initialFrame.content, REQUEST_BITS_NODE_ID_FIELD_OFFSET, bitsNodeId);
encodeLong(initialFrame.content, REQUEST_ALLOWED_FUTURE_MILLIS_FIELD_OFFSET, allowedFutureMillis);
clientMessage.add(initialFrame);
StringCodec.encode(clientMessage, name);
return clientMessage;
Expand All @@ -111,9 +132,12 @@ public static DynamicConfigAddFlakeIdGeneratorConfigCodec.RequestParameters deco
ClientMessage.Frame initialFrame = iterator.next();
request.prefetchCount = decodeInt(initialFrame.content, REQUEST_PREFETCH_COUNT_FIELD_OFFSET);
request.prefetchValidity = decodeLong(initialFrame.content, REQUEST_PREFETCH_VALIDITY_FIELD_OFFSET);
request.idOffset = decodeLong(initialFrame.content, REQUEST_ID_OFFSET_FIELD_OFFSET);
request.statisticsEnabled = decodeBoolean(initialFrame.content, REQUEST_STATISTICS_ENABLED_FIELD_OFFSET);
request.nodeIdOffset = decodeLong(initialFrame.content, REQUEST_NODE_ID_OFFSET_FIELD_OFFSET);
request.epochStart = decodeLong(initialFrame.content, REQUEST_EPOCH_START_FIELD_OFFSET);
request.bitsSequence = decodeInt(initialFrame.content, REQUEST_BITS_SEQUENCE_FIELD_OFFSET);
request.bitsNodeId = decodeInt(initialFrame.content, REQUEST_BITS_NODE_ID_FIELD_OFFSET);
request.allowedFutureMillis = decodeLong(initialFrame.content, REQUEST_ALLOWED_FUTURE_MILLIS_FIELD_OFFSET);
request.name = StringCodec.decode(iterator);
return request;
}
Expand Down
Expand Up @@ -46,8 +46,11 @@ protected IdentifiedDataSerializable getConfig() {
FlakeIdGeneratorConfig config = new FlakeIdGeneratorConfig(parameters.name);
config.setPrefetchCount(parameters.prefetchCount);
config.setPrefetchValidityMillis(parameters.prefetchValidity);
config.setIdOffset(parameters.idOffset);
config.setNodeIdOffset(parameters.nodeIdOffset);
config.setEpochStart(parameters.epochStart);
config.setBitsSequence(parameters.bitsSequence);
config.setBitsNodeId(parameters.bitsNodeId);
config.setAllowedFutureMillis(parameters.allowedFutureMillis);
config.setStatisticsEnabled(parameters.statisticsEnabled);
return config;
}
Expand Down
Expand Up @@ -1439,8 +1439,11 @@ private static void flakeIdGeneratorXmlGenerator(XmlGenerator gen, Config config
gen.open("flake-id-generator", "name", m.getName())
.node("prefetch-count", m.getPrefetchCount())
.node("prefetch-validity-millis", m.getPrefetchValidityMillis())
.node("id-offset", m.getIdOffset())
.node("epoch-start", m.getEpochStart())
.node("node-id-offset", m.getNodeIdOffset())
.node("bits-sequence", m.getBitsSequence())
.node("bits-node-id", m.getBitsNodeId())
.node("allowed-future-millis", m.getAllowedFutureMillis())
.node("statistics-enabled", m.isStatisticsEnabled());
gen.close();
}
Expand Down

0 comments on commit 7119690

Please sign in to comment.