Skip to content

HDDS-15145. Use enum for the ID type in SequenceIdGenerator#10211

Open
navinko wants to merge 1 commit intoapache:masterfrom
navinko:HDDS-15145
Open

HDDS-15145. Use enum for the ID type in SequenceIdGenerator#10211
navinko wants to merge 1 commit intoapache:masterfrom
navinko:HDDS-15145

Conversation

@navinko
Copy link
Copy Markdown
Contributor

@navinko navinko commented May 7, 2026

What changes were proposed in this pull request?

HDDS-15145. Use enum for the ID type in SequenceIdGenerator

Please describe your PR in detail:

  1. 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>.

  2. This gives compile-time safety for supported sequence ID types while preserving the existing RocksDB key strings through "SequenceIdType#getDbKey()".

  3. The existing String constants in SequenceIdGenerator are retained and now mapped with Enum .

  • localId, delTxnId, containerId, CertificateId, rootCertificateId
  • ROOT_CERTIFICATE_ID` remains deprecated, as it was already deprecated before this change.
  1. StateManager and StateManagerImpl continue to use String parameters for allocateBatch and getLastId and did not change it to adapt Enum.

  2. Added unit tests for SequenceIdType and updated existing SequenceIdGenerator and RootCARotationManager tests

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:

% docker compose logs -f scm1.org 2>&1 | grep -E "SequenceId|Allocate a batch|LOCAL_ID|CONTAINER_ID|DEL_TXN_ID|CERTIFICATE_ID"
scm1.org-1 | 2026-05-07 15:16:52,658 [main] INFO ha.SequenceIdGenerator: upgrade localId to 117883640217600000
scm1.org-1 | 2026-05-07 15:16:52,659 [main] INFO ha.SequenceIdGenerator: upgrade delTxnId to 0
scm1.org-1 | 2026-05-07 15:16:52,660 [main] INFO ha.SequenceIdGenerator: upgrade containerId to 0
scm1.org-1 | 2026-05-07 15:16:52,661 [main] INFO ha.SequenceIdGenerator: upgrade CertificateId to 2
scm1.org-1 | 2026-05-07 15:16:52,661 [main] INFO ha.SequenceIdGenerator: Init the HA SequenceIdGenerator.
scm1.org-1 | 2026-05-07 15:16:52,789 [main] INFO ha.SequenceIdGenerator: upgrade CertificateId to 2
scm1.org-1 | 2026-05-07 15:16:59,759 [fbb8e2fd-528a-4709-b43d-bb76bb2569e8@group-665F4C1A70A7-StateMachineUpdater] WARN ha.SequenceIdGenerator: Failed to allocate a batch for CertificateId, expected lastId is 0, actual lastId is 2.
scm1.org-1 | 2026-05-07 15:16:59,762 [IPC Server handler 0 on default port 9961] INFO ha.SequenceIdGenerator: Allocate a batch for CERTIFICATE_ID, change lastId from 2 to 3.
scm1.org-1 | 2026-05-07 15:17:02,868 [IPC Server handler 0 on default port 9961] INFO ha.SequenceIdGenerator: Allocate a batch for CERTIFICATE_ID, change lastId from 3 to 4.
scm1.org-1 | 2026-05-07 15:17:03,472 [IPC Server handler 0 on default port 9961] INFO ha.SequenceIdGenerator: Allocate a batch for CERTIFICATE_ID, change lastId from 4 to 5.
scm1.org-1 | 2026-05-07 15:17:08,742 [IPC Server handler 0 on default port 9961] INFO ha.SequenceIdGenerator: Allocate a batch for CERTIFICATE_ID, change lastId from 5 to 6.
scm1.org-1 | 2026-05-07 15:17:08,774 [IPC Server handler 1 on default port 9961] INFO ha.SequenceIdGenerator: Allocate a batch for CERTIFICATE_ID, change lastId from 6 to 7.
scm1.org-1 | 2026-05-07 15:17:08,804 [IPC Server handler 0 on default port 9961] INFO ha.SequenceIdGenerator: Allocate a batch for CERTIFICATE_ID, change lastId from 7 to 8.
scm1.org-1 | 2026-05-07 15:17:10,129 [IPC Server handler 0 on default port 9961] INFO ha.SequenceIdGenerator: Allocate a batch for CERTIFICATE_ID, change lastId from 8 to 9.
scm1.org-1 | 2026-05-07 15:17:10,180 [IPC Server handler 1 on default port 9961] INFO ha.SequenceIdGenerator: Allocate a batch for CERTIFICATE_ID, change lastId from 9 to 10.
scm1.org-1 | 2026-05-07 15:17:10,208 [IPC Server handler 0 on default port 9961] INFO ha.SequenceIdGenerator: Allocate a batch for CERTIFICATE_ID, change lastId from 10 to 11.
scm1.org-1 | 2026-05-07 15:21:35,259 [IPC Server handler 0 on default port 9860] INFO ha.SequenceIdGenerator: Allocate a batch for CONTAINER_ID, change lastId from 0 to 1000.
scm1.org-1 | 2026-05-07 15:24:17,941 [fbb8e2fd-528a-4709-b43d-bb76bb2569e8@group-665F4C1A70A7-StateMachineUpdater] WARN ha.SequenceIdGenerator: Failed to allocate a batch for localId, expected lastId is 0, actual lastId is 117883640217600000.
scm1.org-1 | 2026-05-07 15:24:17,944 [IPC Server handler 1 on default port 9863] INFO ha.SequenceIdGenerator: Allocate a batch for LOCAL_ID, change lastId from 117883640217600000 to 117883640217601000.
scm1.org-1 | 2026-05-07 15:28:13,694 [IPC Server handler 88 on default port 9863] INFO ha.SequenceIdGenerator: Allocate a batch for DEL_TXN_ID, change lastId from 0 to 1000.

Successful CI : https://github.com/navinko/ozone/actions/runs/25504128377

Copy link
Copy Markdown
Contributor

@sreejasahithi sreejasahithi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @navinko

Comment on lines +54 to +59
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);
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Comment on lines +87 to +91
@Test
public void testReturnsNullIfEnumConstantNotAvailable() {
assertNull(SequenceIdType.fromDbKey("unmapped-key-string"));
assertNull(SequenceIdType.fromDbKey(null));
}
Copy link
Copy Markdown
Contributor

@sreejasahithi sreejasahithi May 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Copy Markdown
Contributor

@szetszwo szetszwo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@navinko , thanks for working on this! Please see the comments inlined.

/**
* Returns the {@link SequenceIdType} corresponding to the provided RocksDB key string, or null if unmapped.
*/
public static SequenceIdType fromDbKey(String dbKey) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Comment on lines +67 to +75
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();
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Change them to private.

public SequenceIdGenerator(ConfigurationSource conf,
SCMHAManager scmhaManager, Table<String, Long> sequenceIdTable) {
this.sequenceIdToBatchMap = new HashMap<>();
this.sequenceIdToBatchMap = new EnumMap<>(SequenceIdType.class);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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);
  }

Comment on lines 117 to +118
Batch batch = sequenceIdToBatchMap.computeIfAbsent(
sequenceIdName, key -> new Batch());
idType, key -> new Batch());
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use get()

      final Batch batch = sequenceIdToBatchMap.get(idType);


// reload lastId from RocksDB.
batch.lastId = stateManager.getLastId(sequenceIdName);
batch.lastId = stateManager.getLastId(idType.getDbKey());
Copy link
Copy Markdown
Contributor

@szetszwo szetszwo May 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • Change the parameter to SequenceIdType
  • Change StateManagerImpl.sequenceIdToLastIdMap key to SequenceIdType

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants