HDDS-15145. Use enum for the ID type in SequenceIdGenerator#10211
Conversation
| public void testNumberOfEnumConstants() { | ||
| // If a new SequenceIdType is added, this test will fail. | ||
| // This serves as a reminder to the developer to verify RocksDB backward | ||
| // compatibility and update this test class accordingly. | ||
| assertEquals(5, SequenceIdType.values().length); | ||
| } |
There was a problem hiding this comment.
Here testNumberOfEnumConstants (assertEquals(5, SequenceIdType.values().length)) is fully subsumed by testIfNewEnumConstantGetsAdded. Every failure scenario that testNumberOfEnumConstants catches is also caught by testIfNewEnumConstantGetsAdded, which additionally catches renames (count stays 5 but a name changes), and provides a far more descriptive failure message with the "ACTION REQUIRED" instruction.
There was a problem hiding this comment.
Thanks , it make sense!
removed this one.
| @Test | ||
| public void testReturnsNullIfEnumConstantNotAvailable() { | ||
| assertNull(SequenceIdType.fromDbKey("unmapped-key-string")); | ||
| assertNull(SequenceIdType.fromDbKey(null)); | ||
| } |
There was a problem hiding this comment.
We can in a different test consider asserting assertSame(type, fromDbKey(type.getDbKey())) for every constant so the static map stays aligned with getDbKey(), not covered by the unknown/null case alone.
There was a problem hiding this comment.
Thanks @sreejasahithi for review, to align with current review comments i ahve removed the unused method fromDbKey completely.
| /** | ||
| * Returns the {@link SequenceIdType} corresponding to the provided RocksDB key string, or null if unmapped. | ||
| */ | ||
| public static SequenceIdType fromDbKey(String dbKey) { |
There was a problem hiding this comment.
This method is unused except testReturnsNullIfEnumConstantNotAvailable(). Let's remove it and also DB_KEY_MAP.
Indeed, we should always use SequenceIdType and never convert a String to SequenceIdType.
| public static final String LOCAL_ID = SequenceIdType.LOCAL_ID.getDbKey(); | ||
| public static final String DEL_TXN_ID = SequenceIdType.DEL_TXN_ID.getDbKey(); | ||
| public static final String CONTAINER_ID = SequenceIdType.CONTAINER_ID.getDbKey(); | ||
|
|
||
| // Certificate ID for all services, including root certificates, whose ID | ||
| // were using "rootCertificateId" before. | ||
| public static final String CERTIFICATE_ID = "CertificateId"; | ||
| public static final String CERTIFICATE_ID = SequenceIdType.CERTIFICATE_ID.getDbKey(); | ||
| @Deprecated | ||
| public static final String ROOT_CERTIFICATE_ID = "rootCertificateId"; | ||
| public static final String ROOT_CERTIFICATE_ID = SequenceIdType.ROOT_CERTIFICATE_ID.getDbKey(); |
| public SequenceIdGenerator(ConfigurationSource conf, | ||
| SCMHAManager scmhaManager, Table<String, Long> sequenceIdTable) { | ||
| this.sequenceIdToBatchMap = new HashMap<>(); | ||
| this.sequenceIdToBatchMap = new EnumMap<>(SequenceIdType.class); |
There was a problem hiding this comment.
Make it unmodifiable:
this.sequenceIdToBatchMap = newSequenceIdToBatchMap(); static Map<SequenceIdType, Batch> newSequenceIdToBatchMap() {
final EnumMap<SequenceIdType, Batch> map = new EnumMap<>(SequenceIdType.class);
for (SequenceIdType type : SequenceIdType.values()) {
map.put(type, new Batch());
}
return Collections.unmodifiableMap(map);
}| Batch batch = sequenceIdToBatchMap.computeIfAbsent( | ||
| sequenceIdName, key -> new Batch()); | ||
| idType, key -> new Batch()); |
There was a problem hiding this comment.
Use get()
final Batch batch = sequenceIdToBatchMap.get(idType);|
|
||
| // reload lastId from RocksDB. | ||
| batch.lastId = stateManager.getLastId(sequenceIdName); | ||
| batch.lastId = stateManager.getLastId(idType.getDbKey()); |
There was a problem hiding this comment.
- Change the parameter to SequenceIdType
- Change StateManagerImpl.sequenceIdToLastIdMap key to SequenceIdType
There was a problem hiding this comment.
Thanks @sreejasahithi @szetszwo for the suggestion!
I have removed the unused method fromDbKey and DB_KEY_MAP and made all constant under SequenceIdGenerator private alongwith EnumMap as unmodifiable and dis suggested changes in test classes.
I've updated code for StateManagerImpl too , the parameters and map keys to use SequenceIdType instead of Strings. Further , to handle how these new Enums are serialized across the Ratis and safely deserialized from existing RocksDB bytes, I implemented the ScmSequenceIdTypeCodec and registered with ScmCodecFactory. This ensures the Enums translate perfectly into our legacy byte format .
Also referred existing TestPipelineIDCodec to create new unit test for codec and verifies the serialization and deserialzation. In the LegacyStringSequenceIdCodecForTesting class simulated, how Sequence IDs were serialized before the Enum refactoring.
|
Thanks @szetszwo @sreejasahithi for the review , tried addressing review suggestions . |
szetszwo
left a comment
There was a problem hiding this comment.
- Change the parameter to SequenceIdType
- Change StateManagerImpl.sequenceIdToLastIdMap key to SequenceIdType
@navinko , my suggestions above actually need a lot of changes. Sorry that I was not aware of it!
Could you revert them here and do it in a separated JIRA, revert all the changes for StateManager and StateManagerImpl and keep using String?
| */ | ||
| @Replicate | ||
| Boolean allocateBatch(String sequenceIdName, | ||
| Boolean allocateBatch(SequenceIdType idType, |
There was a problem hiding this comment.
We cannot change the parameter class for compatibility. Otherwise, the SCM in old version cannot talk to the SCM in new version. Let's do it in a separated JIRA.
There was a problem hiding this comment.
Thanks @szetszwo will update the PR as suggested .
|
@navinko , thanks for the update! Please remove |
|
Thanks @szetszwo , reverted all the changes for StateManager and StateManagerImpl and keep using String. |
| /** | ||
| * Represents the sequence ID types managed by {@link SequenceIdGenerator} and their persisted RocksDB keys. | ||
| */ | ||
| public enum SequenceIdType { |
There was a problem hiding this comment.
@navinko , Thanks for the update!
After some thoughts, .let's simply use the db key as the enum names. Otherwise, it is confusing to have two different strings.
public enum SequenceIdType {
localId,
delTxnId,
containerId,
/** Certificate ID for all services, including root certificates. */
CertificateId,
/** @deprecated Use {@link #CERTIFICATE_ID} instead. */
@Deprecated
rootCertificateId;
}The change looks good other than that.
There was a problem hiding this comment.
Thanks @szetszwo for the review . Agreed , will update the change shortly.
There was a problem hiding this comment.
Thanks @szetszwo
I just updated the changes ,tried incorporating the suggestions.
- used enum constants same as db key
- refactored related code ,test cases and updated required comments .
- tested with existing and updated test cases .ran locally with docker secure cluster and verified allocation paths and updated under "How was this patch tested"
- CI build progressing
szetszwo
left a comment
There was a problem hiding this comment.
+1 the change looks good.
|
@navinko , filed HDDS-15288 for improving StateManagerImpl. Please see if you are interested working on it. |
Thanks for the review and merge . Sure will assign myself and start working on it. |
What changes were proposed in this pull request?
HDDS-15145. Use enum for the ID type in SequenceIdGenerator
Please describe your PR in detail:
This PR introduces "SequenceIdType" to replace String based ID type arguments in "SequenceIdGenerator".
SequenceIdGenerator#getNextId now accepts "SequenceIdType" instead of String values, and its in-memory batch cache uses an EnumMap<SequenceIdType, Batch>.
This gives compile-time safety for supported sequence ID types while preserving the existing RocksDB key strings through "SequenceIdType#getDbKey()".
The existing String constants in
SequenceIdGeneratorare retained and now mapped with Enum .[Reverted]Updated StateManager and StateManagerImpl to use Enum instead of String as sequenceID and created new codec for it. parameters for allocateBatch and getLastId are now updated to adapt Enum.
Added unit tests for SequenceIdType and updated existing SequenceIdGenerator and RootCARotationManager
tests
[Removed] Last Created new test for Codec
TestScmSequenceIdTypeCodec
LegacyStringSequenceIdCodecForTesting
What is the link to the Apache JIRA
https://issues.apache.org/jira/browse/HDDS-15145
How was this patch tested?
Validated with unit test and Also verified the change in a local Docker compose secure HA cluster. The SCM logs show enum-based allocation paths:
Latest progressing CI : https://github.com/navinko/ozone/actions/runs/25883196408